feat(ui): add IAICollapse for parameters

This commit is contained in:
psychedelicious 2023-05-08 19:05:43 +10:00
parent 864f4bb4af
commit 33c69359c2
66 changed files with 1076 additions and 572 deletions

View File

@ -454,9 +454,10 @@
"seed": "Seed", "seed": "Seed",
"imageToImage": "Image to Image", "imageToImage": "Image to Image",
"randomizeSeed": "Randomize Seed", "randomizeSeed": "Randomize Seed",
"shuffle": "Shuffle", "shuffle": "Shuffle Seed",
"noiseThreshold": "Noise Threshold", "noiseThreshold": "Noise Threshold",
"perlinNoise": "Perlin Noise", "perlinNoise": "Perlin Noise",
"noiseSettings": "Noise",
"variations": "Variations", "variations": "Variations",
"variationAmount": "Variation Amount", "variationAmount": "Variation Amount",
"seedWeights": "Seed Weights", "seedWeights": "Seed Weights",
@ -471,6 +472,8 @@
"scale": "Scale", "scale": "Scale",
"otherOptions": "Other Options", "otherOptions": "Other Options",
"seamlessTiling": "Seamless Tiling", "seamlessTiling": "Seamless Tiling",
"seamlessXAxis": "X Axis",
"seamlessYAxis": "Y Axis",
"hiresOptim": "High Res Optimization", "hiresOptim": "High Res Optimization",
"hiresStrength": "High Res Strength", "hiresStrength": "High Res Strength",
"imageFit": "Fit Initial Image To Output Size", "imageFit": "Fit Initial Image To Output Size",

View File

@ -10,7 +10,7 @@ const moduleLog = log.child({ namespace: 'invoke' });
export const addUserInvokedCreateListener = () => { export const addUserInvokedCreateListener = () => {
startAppListening({ startAppListening({
predicate: (action): action is ReturnType<typeof userInvoked> => predicate: (action): action is ReturnType<typeof userInvoked> =>
userInvoked.match(action) && action.payload === 'generate', userInvoked.match(action) && action.payload === 'text',
effect: (action, { getState, dispatch }) => { effect: (action, { getState, dispatch }) => {
const state = getState(); const state = getState();

View File

@ -0,0 +1,61 @@
import { ChevronDownIcon, ChevronUpIcon } from '@chakra-ui/icons';
import { Box, Collapse, Flex, Spacer, Switch } from '@chakra-ui/react';
import { PropsWithChildren, memo } from 'react';
export type IAIToggleCollapseProps = PropsWithChildren & {
label: string;
isOpen: boolean;
onToggle: () => void;
withSwitch?: boolean;
};
const IAICollapse = (props: IAIToggleCollapseProps) => {
const { label, isOpen, onToggle, children, withSwitch = false } = props;
return (
<Box>
<Flex
onClick={onToggle}
sx={{
alignItems: 'center',
p: 2,
px: 4,
borderTopRadius: 'base',
borderBottomRadius: isOpen ? 0 : 'base',
bg: isOpen ? 'base.750' : 'base.800',
color: 'base.100',
_hover: {
bg: isOpen ? 'base.700' : 'base.750',
},
fontSize: 'sm',
fontWeight: 600,
cursor: 'pointer',
transitionProperty: 'common',
transitionDuration: 'normal',
userSelect: 'none',
}}
>
{label}
<Spacer />
{withSwitch && <Switch isChecked={isOpen} pointerEvents="none" />}
{!withSwitch && (
<ChevronUpIcon
sx={{
w: '1rem',
h: '1rem',
transform: isOpen ? 'rotate(0deg)' : 'rotate(180deg)',
transitionProperty: 'common',
transitionDuration: 'normal',
}}
/>
)}
</Flex>
<Collapse in={isOpen} animateOpacity>
<Box sx={{ p: 4, borderBottomRadius: 'base', bg: 'base.800' }}>
{children}
</Box>
</Collapse>
</Box>
);
};
export default memo(IAICollapse);

View File

@ -4,7 +4,7 @@ import IAISlider from 'common/components/IAISlider';
import { setSeamBlur } from 'features/parameters/store/generationSlice'; import { setSeamBlur } from 'features/parameters/store/generationSlice';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
export default function SeamBlur() { export default function ParamSeamBlur() {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const seamBlur = useAppSelector( const seamBlur = useAppSelector(
(state: RootState) => state.generation.seamBlur (state: RootState) => state.generation.seamBlur

View File

@ -4,7 +4,7 @@ import IAISlider from 'common/components/IAISlider';
import { setSeamSize } from 'features/parameters/store/generationSlice'; import { setSeamSize } from 'features/parameters/store/generationSlice';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
export default function SeamSize() { export default function ParamSeamSize() {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { t } = useTranslation(); const { t } = useTranslation();

View File

@ -4,7 +4,7 @@ import IAISlider from 'common/components/IAISlider';
import { setSeamSteps } from 'features/parameters/store/generationSlice'; import { setSeamSteps } from 'features/parameters/store/generationSlice';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
export default function SeamSteps() { export default function ParamSeamSteps() {
const { t } = useTranslation(); const { t } = useTranslation();
const seamSteps = useAppSelector( const seamSteps = useAppSelector(
(state: RootState) => state.generation.seamSteps (state: RootState) => state.generation.seamSteps

View File

@ -4,7 +4,7 @@ import IAISlider from 'common/components/IAISlider';
import { setSeamStrength } from 'features/parameters/store/generationSlice'; import { setSeamStrength } from 'features/parameters/store/generationSlice';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
export default function SeamStrength() { export default function ParamSeamStrength() {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { t } = useTranslation(); const { t } = useTranslation();
const seamStrength = useAppSelector( const seamStrength = useAppSelector(

View File

@ -1,16 +1,16 @@
import { VStack } from '@chakra-ui/react'; import { VStack } from '@chakra-ui/react';
import SeamBlur from './SeamBlur'; import ParamSeamBlur from './ParamSeamBlur';
import SeamSize from './SeamSize'; import ParamSeamSize from './ParamSeamSize';
import SeamSteps from './SeamSteps'; import ParamSeamSteps from './ParamSeamSteps';
import SeamStrength from './SeamStrength'; import ParamSeamStrength from './ParamSeamStrength';
const SeamCorrectionSettings = () => { const SeamCorrectionSettings = () => {
return ( return (
<VStack gap={2} alignItems="stretch"> <VStack gap={2} alignItems="stretch">
<SeamSize /> <ParamSeamSize />
<SeamBlur /> <ParamSeamBlur />
<SeamStrength /> <ParamSeamStrength />
<SeamSteps /> <ParamSeamSteps />
</VStack> </VStack>
); );
}; };

View File

@ -1,12 +0,0 @@
import { VStack } from '@chakra-ui/react';
import SeamlessSettings from './SeamlessSettings';
const ImageToImageOutputSettings = () => {
return (
<VStack gap={2} alignItems="stretch">
<SeamlessSettings />
</VStack>
);
};
export default ImageToImageOutputSettings;

View File

@ -1,15 +0,0 @@
import { VStack } from '@chakra-ui/react';
import { HiresStrength, HiresToggle } from './HiresSettings';
import SeamlessSettings from './SeamlessSettings';
const OutputSettings = () => {
return (
<VStack gap={2} alignItems="stretch">
<SeamlessSettings />
<HiresToggle />
<HiresStrength />
</VStack>
);
};
export default OutputSettings;

View File

@ -1,54 +0,0 @@
import { VStack } from '@chakra-ui/react';
import { RootState } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAISlider from 'common/components/IAISlider';
import {
setHorizontalSymmetrySteps,
setVerticalSymmetrySteps,
} from 'features/parameters/store/generationSlice';
import { useTranslation } from 'react-i18next';
export default function SymmetrySettings() {
const horizontalSymmetrySteps = useAppSelector(
(state: RootState) => state.generation.horizontalSymmetrySteps
);
const verticalSymmetrySteps = useAppSelector(
(state: RootState) => state.generation.verticalSymmetrySteps
);
const steps = useAppSelector((state: RootState) => state.generation.steps);
const dispatch = useAppDispatch();
const { t } = useTranslation();
return (
<VStack gap={2} alignItems="stretch">
<IAISlider
label={t('parameters.hSymmetryStep')}
value={horizontalSymmetrySteps}
onChange={(v) => dispatch(setHorizontalSymmetrySteps(v))}
min={0}
max={steps}
step={1}
withInput
withSliderMarks
withReset
handleReset={() => dispatch(setHorizontalSymmetrySteps(0))}
/>
<IAISlider
label={t('parameters.vSymmetryStep')}
value={verticalSymmetrySteps}
onChange={(v) => dispatch(setVerticalSymmetrySteps(v))}
min={0}
max={steps}
step={1}
withInput
withSliderMarks
withReset
handleReset={() => dispatch(setVerticalSymmetrySteps(0))}
/>
</VStack>
);
}

View File

@ -1,20 +0,0 @@
import { VStack } from '@chakra-ui/react';
import Perlin from './Perlin';
import RandomizeSeed from './RandomizeSeed';
import Seed from './Seed';
import Threshold from './Threshold';
/**
* Seed & variation options. Includes iteration, seed, seed randomization, variation options.
*/
const SeedSettings = () => {
return (
<VStack gap={2} alignItems="stretch">
<Seed />
<Threshold />
<Perlin />
</VStack>
);
};
export default SeedSettings;

View File

@ -1,25 +0,0 @@
import { RootState } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAISwitch from 'common/components/IAISwitch';
import { setShouldGenerateVariations } from 'features/parameters/store/generationSlice';
import { ChangeEvent } from 'react';
export default function GenerateVariationsToggle() {
const shouldGenerateVariations = useAppSelector(
(state: RootState) => state.generation.shouldGenerateVariations
);
const dispatch = useAppDispatch();
const handleChangeShouldGenerateVariations = (
e: ChangeEvent<HTMLInputElement>
) => dispatch(setShouldGenerateVariations(e.target.checked));
return (
<IAISwitch
isChecked={shouldGenerateVariations}
width="auto"
onChange={handleChangeShouldGenerateVariations}
/>
);
}

View File

@ -1,17 +0,0 @@
import { VStack } from '@chakra-ui/react';
import SeedWeights from './SeedWeights';
import VariationAmount from './VariationAmount';
/**
* Seed & variation options. Includes iteration, seed, seed randomization, variation options.
*/
const VariationsSettings = () => {
return (
<VStack gap={2} alignItems="stretch">
<VariationAmount />
<SeedWeights />
</VStack>
);
};
export default VariationsSettings;

View File

@ -1,14 +1,15 @@
import { memo } from 'react';
import { Box, Flex, VStack } from '@chakra-ui/react'; import { Box, Flex, VStack } from '@chakra-ui/react';
import { RootState } from 'app/store/store'; import { RootState } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import ModelSelect from 'features/system/components/ModelSelect'; import ModelSelect from 'features/system/components/ModelSelect';
import { memo } from 'react'; import ParamHeight from 'features/parameters/components/Parameters/ParamHeight';
import HeightSlider from './HeightSlider'; import ParamCFGScale from 'features/parameters/components/Parameters/ParamCFGScale';
import MainCFGScale from './MainCFGScale'; import ParamIterations from 'features/parameters/components/Parameters/ParamIterations';
import MainIterations from './MainIterations'; import ParamScheduler from 'features/parameters/components/Parameters/ParamScheduler';
import MainSampler from './MainSampler'; import ParamSteps from 'features/parameters/components/Parameters/ParamSteps';
import MainSteps from './MainSteps'; import ParamWidth from 'features/parameters/components/Parameters/ParamWidth';
import WidthSlider from './WidthSlider';
const MainSettings = () => { const MainSettings = () => {
const shouldUseSliders = useAppSelector( const shouldUseSliders = useAppSelector(
@ -17,14 +18,14 @@ const MainSettings = () => {
return shouldUseSliders ? ( return shouldUseSliders ? (
<VStack gap={2}> <VStack gap={2}>
<MainIterations /> <ParamIterations />
<MainSteps /> <ParamSteps />
<MainCFGScale /> <ParamCFGScale />
<WidthSlider /> <ParamWidth />
<HeightSlider /> <ParamHeight />
<Flex gap={3} w="full"> <Flex gap={3} w="full">
<Box flexGrow={2}> <Box flexGrow={2}>
<MainSampler /> <ParamScheduler />
</Box> </Box>
<Box flexGrow={3}> <Box flexGrow={3}>
<ModelSelect /> <ModelSelect />
@ -34,15 +35,15 @@ const MainSettings = () => {
) : ( ) : (
<Flex gap={3} flexDirection="column"> <Flex gap={3} flexDirection="column">
<Flex gap={3}> <Flex gap={3}>
<MainIterations /> <ParamIterations />
<MainSteps /> <ParamSteps />
<MainCFGScale /> <ParamCFGScale />
</Flex> </Flex>
<WidthSlider /> <ParamWidth />
<HeightSlider /> <ParamHeight />
<Flex gap={3} w="full"> <Flex gap={3} w="full">
<Box flexGrow={2}> <Box flexGrow={2}>
<MainSampler /> <ParamScheduler />
</Box> </Box>
<Box flexGrow={3}> <Box flexGrow={3}>
<ModelSelect /> <ModelSelect />

View File

@ -0,0 +1,37 @@
import { Flex } from '@chakra-ui/react';
import { useTranslation } from 'react-i18next';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { RootState } from 'app/store/store';
import IAICollapse from 'common/components/IAICollapse';
import { memo } from 'react';
import { ParamHiresStrength } from './ParamHiresStrength';
import { setHiresFix } from 'features/parameters/store/postprocessingSlice';
/**
* Seed & variation options. Includes iteration, seed, seed randomization, variation options.
*/
const ParamHiresCollapse = () => {
const { t } = useTranslation();
const hiresFix = useAppSelector(
(state: RootState) => state.postprocessing.hiresFix
);
const dispatch = useAppDispatch();
const handleToggle = () => dispatch(setHiresFix(!hiresFix));
return (
<IAICollapse
label={t('parameters.hiresOptim')}
isOpen={hiresFix}
onToggle={handleToggle}
withSwitch
>
<Flex sx={{ gap: 2, flexDirection: 'column' }}>
<ParamHiresStrength />
</Flex>
</IAICollapse>
);
};
export default memo(ParamHiresCollapse);

View File

@ -0,0 +1,3 @@
// TODO
export default {};

View File

@ -0,0 +1,3 @@
// TODO
export default {};

View File

@ -1,15 +1,9 @@
import { createSelector } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
import type { RootState } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAISlider from 'common/components/IAISlider'; import IAISlider from 'common/components/IAISlider';
import IAISwitch from 'common/components/IAISwitch';
import { postprocessingSelector } from 'features/parameters/store/postprocessingSelectors'; import { postprocessingSelector } from 'features/parameters/store/postprocessingSelectors';
import { import { setHiresStrength } from 'features/parameters/store/postprocessingSlice';
setHiresFix,
setHiresStrength,
} from 'features/parameters/store/postprocessingSlice';
import { isEqual } from 'lodash-es'; import { isEqual } from 'lodash-es';
import { ChangeEvent } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
const hiresStrengthSelector = createSelector( const hiresStrengthSelector = createSelector(
@ -22,7 +16,7 @@ const hiresStrengthSelector = createSelector(
} }
); );
export const HiresStrength = () => { export const ParamHiresStrength = () => {
const { hiresFix, hiresStrength } = useAppSelector(hiresStrengthSelector); const { hiresFix, hiresStrength } = useAppSelector(hiresStrengthSelector);
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
@ -55,28 +49,3 @@ export const HiresStrength = () => {
/> />
); );
}; };
/**
* Hires Fix Toggle
*/
export const HiresToggle = () => {
const dispatch = useAppDispatch();
const hiresFix = useAppSelector(
(state: RootState) => state.postprocessing.hiresFix
);
const { t } = useTranslation();
const handleChangeHiresFix = (e: ChangeEvent<HTMLInputElement>) =>
dispatch(setHiresFix(e.target.checked));
return (
<IAISwitch
label={t('parameters.hiresOptim')}
fontSize="md"
isChecked={hiresFix}
onChange={handleChangeHiresFix}
/>
);
};

View File

@ -0,0 +1,31 @@
import type { RootState } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAISwitch from 'common/components/IAISwitch';
import { setHiresFix } from 'features/parameters/store/postprocessingSlice';
import { ChangeEvent } from 'react';
import { useTranslation } from 'react-i18next';
/**
* Hires Fix Toggle
*/
export const ParamHiresToggle = () => {
const dispatch = useAppDispatch();
const hiresFix = useAppSelector(
(state: RootState) => state.postprocessing.hiresFix
);
const { t } = useTranslation();
const handleChangeHiresFix = (e: ChangeEvent<HTMLInputElement>) =>
dispatch(setHiresFix(e.target.checked));
return (
<IAISwitch
label={t('parameters.hiresOptim')}
fontSize="md"
isChecked={hiresFix}
onChange={handleChangeHiresFix}
/>
);
};

View File

@ -0,0 +1,3 @@
// TODO
export default {};

View File

@ -0,0 +1,37 @@
import { useTranslation } from 'react-i18next';
import { Flex } from '@chakra-ui/react';
import IAICollapse from 'common/components/IAICollapse';
import ParamPerlinNoise from './ParamPerlinNoise';
import ParamNoiseThreshold from './ParamNoiseThreshold';
import { RootState } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { setShouldUseNoiseSettings } from 'features/parameters/store/generationSlice';
import { memo } from 'react';
const ParamNoiseCollapse = () => {
const { t } = useTranslation();
const shouldUseNoiseSettings = useAppSelector(
(state: RootState) => state.generation.shouldUseNoiseSettings
);
const dispatch = useAppDispatch();
const handleToggle = () =>
dispatch(setShouldUseNoiseSettings(!shouldUseNoiseSettings));
return (
<IAICollapse
label={t('parameters.noiseSettings')}
isOpen={shouldUseNoiseSettings}
onToggle={handleToggle}
withSwitch
>
<Flex sx={{ gap: 2, flexDirection: 'column' }}>
<ParamPerlinNoise />
<ParamNoiseThreshold />
</Flex>
</IAICollapse>
);
};
export default memo(ParamNoiseCollapse);

View File

@ -4,7 +4,7 @@ import IAISlider from 'common/components/IAISlider';
import { setThreshold } from 'features/parameters/store/generationSlice'; import { setThreshold } from 'features/parameters/store/generationSlice';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
export default function Threshold() { export default function ParamNoiseThreshold() {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const threshold = useAppSelector( const threshold = useAppSelector(
(state: RootState) => state.generation.threshold (state: RootState) => state.generation.threshold

View File

@ -4,7 +4,7 @@ import IAISlider from 'common/components/IAISlider';
import { setPerlin } from 'features/parameters/store/generationSlice'; import { setPerlin } from 'features/parameters/store/generationSlice';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
export default function Perlin() { export default function ParamPerlinNoise() {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const perlin = useAppSelector((state: RootState) => state.generation.perlin); const perlin = useAppSelector((state: RootState) => state.generation.perlin);
const { t } = useTranslation(); const { t } = useTranslation();

View File

@ -0,0 +1,18 @@
import { VStack } from '@chakra-ui/react';
import ParamSeamlessToggle from './Seamless/ParamSeamlessToggle';
// import ParamSeamlessAxes from '../../Parameters/Seamless/ParamSeamlessAxes';
import { ParamHiresToggle } from './Hires/ParamHiresToggle';
import { ParamHiresStrength } from './Hires/ParamHiresStrength';
const OtherSettings = () => {
return (
<VStack gap={2} alignItems="stretch">
<ParamSeamlessToggle />
{/* <ParamSeamlessAxes /> */}
<ParamHiresToggle />
<ParamHiresStrength />
</VStack>
);
};
export default OtherSettings;

View File

@ -30,7 +30,7 @@ const selector = createSelector(
} }
); );
const GuidanceScale = () => { const ParamCFGScale = () => {
const { const {
cfgScale, cfgScale,
initial, initial,
@ -82,4 +82,4 @@ const GuidanceScale = () => {
); );
}; };
export default memo(GuidanceScale); export default memo(ParamCFGScale);

View File

@ -31,7 +31,7 @@ const selector = createSelector(
} }
); );
const HeightSlider = () => { const ParamHeight = () => {
const { const {
height, height,
initial, initial,
@ -74,4 +74,4 @@ const HeightSlider = () => {
); );
}; };
export default memo(HeightSlider); export default memo(ParamHeight);

View File

@ -32,7 +32,7 @@ const selector = createSelector(
} }
); );
const MainIterations = () => { const ParamIterations = () => {
const { const {
iterations, iterations,
initial, initial,
@ -83,4 +83,4 @@ const MainIterations = () => {
); );
}; };
export default memo(MainIterations); export default memo(ParamIterations);

View File

@ -4,7 +4,7 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { setNegativePrompt } from 'features/parameters/store/generationSlice'; import { setNegativePrompt } from 'features/parameters/store/generationSlice';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
const NegativePromptInput = () => { const ParamNegativeConditioning = () => {
const negativePrompt = useAppSelector( const negativePrompt = useAppSelector(
(state: RootState) => state.generation.negativePrompt (state: RootState) => state.generation.negativePrompt
); );
@ -29,4 +29,4 @@ const NegativePromptInput = () => {
); );
}; };
export default NegativePromptInput; export default ParamNegativeConditioning;

View File

@ -35,7 +35,7 @@ const promptInputSelector = createSelector(
/** /**
* Prompt input text area. * Prompt input text area.
*/ */
const PromptInput = () => { const ParamPositiveConditioning = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { prompt, activeTabName } = useAppSelector(promptInputSelector); const { prompt, activeTabName } = useAppSelector(promptInputSelector);
const { isReady } = useAppSelector(readinessSelector); const { isReady } = useAppSelector(readinessSelector);
@ -88,4 +88,4 @@ const PromptInput = () => {
); );
}; };
export default PromptInput; export default ParamPositiveConditioning;

View File

@ -6,7 +6,7 @@ import { setSampler } from 'features/parameters/store/generationSlice';
import { ChangeEvent, memo, useCallback } from 'react'; import { ChangeEvent, memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
const Scheduler = () => { const ParamScheduler = () => {
const sampler = useAppSelector( const sampler = useAppSelector(
(state: RootState) => state.generation.sampler (state: RootState) => state.generation.sampler
); );
@ -29,4 +29,4 @@ const Scheduler = () => {
); );
}; };
export default memo(Scheduler); export default memo(ParamScheduler);

View File

@ -36,7 +36,7 @@ const selector = createSelector(
} }
); );
const MainSteps = () => { const ParamSteps = () => {
const { steps, initial, min, sliderMax, inputMax, step, shouldUseSliders } = const { steps, initial, min, sliderMax, inputMax, step, shouldUseSliders } =
useAppSelector(selector); useAppSelector(selector);
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
@ -84,4 +84,4 @@ const MainSteps = () => {
); );
}; };
export default memo(MainSteps); export default memo(ParamSteps);

View File

@ -30,7 +30,7 @@ const selector = createSelector(
} }
); );
const WidthSlider = () => { const ParamWidth = () => {
const { const {
width, width,
initial, initial,
@ -73,4 +73,4 @@ const WidthSlider = () => {
); );
}; };
export default memo(WidthSlider); export default memo(ParamWidth);

View File

@ -0,0 +1,51 @@
import { useTranslation } from 'react-i18next';
import { Box, Flex } from '@chakra-ui/react';
import IAICollapse from 'common/components/IAICollapse';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { setSeamless } from 'features/parameters/store/generationSlice';
import { memo } from 'react';
import { createSelector } from '@reduxjs/toolkit';
import { generationSelector } from 'features/parameters/store/generationSelectors';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import ParamSeamlessXAxis from './ParamSeamlessXAxis';
import ParamSeamlessYAxis from './ParamSeamlessYAxis';
const selector = createSelector(
generationSelector,
(generation) => {
const { shouldUseSeamless, seamlessXAxis, seamlessYAxis } = generation;
return { shouldUseSeamless, seamlessXAxis, seamlessYAxis };
},
defaultSelectorOptions
);
const ParamSeamlessCollapse = () => {
const { t } = useTranslation();
const { shouldUseSeamless, seamlessXAxis, seamlessYAxis } =
useAppSelector(selector);
const dispatch = useAppDispatch();
const handleToggle = () => dispatch(setSeamless(!shouldUseSeamless));
return (
<IAICollapse
label={t('parameters.seamlessTiling')}
isOpen={shouldUseSeamless}
onToggle={handleToggle}
withSwitch
>
<Flex sx={{ gap: 5 }}>
<Box flexGrow={1}>
<ParamSeamlessXAxis />
</Box>
<Box flexGrow={1}>
<ParamSeamlessYAxis />
</Box>
</Flex>
</IAICollapse>
);
};
export default memo(ParamSeamlessCollapse);

View File

@ -8,7 +8,7 @@ import { useTranslation } from 'react-i18next';
/** /**
* Seamless tiling toggle * Seamless tiling toggle
*/ */
const SeamlessSettings = () => { const ParamSeamlessToggle = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const seamless = useAppSelector( const seamless = useAppSelector(
@ -30,4 +30,4 @@ const SeamlessSettings = () => {
); );
}; };
export default SeamlessSettings; export default ParamSeamlessToggle;

View File

@ -0,0 +1,43 @@
import { useTranslation } from 'react-i18next';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { ChangeEvent, memo, useCallback } from 'react';
import { createSelector } from '@reduxjs/toolkit';
import { generationSelector } from 'features/parameters/store/generationSelectors';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAISwitch from 'common/components/IAISwitch';
import { setSeamlessXAxis } from 'features/parameters/store/generationSlice';
const selector = createSelector(
generationSelector,
(generation) => {
const { seamlessXAxis } = generation;
return { seamlessXAxis };
},
defaultSelectorOptions
);
const ParamSeamlessXAxis = () => {
const { t } = useTranslation();
const { seamlessXAxis } = useAppSelector(selector);
const dispatch = useAppDispatch();
const handleChange = useCallback(
(e: ChangeEvent<HTMLInputElement>) => {
dispatch(setSeamlessXAxis(e.target.checked));
},
[dispatch]
);
return (
<IAISwitch
label={t('parameters.seamlessXAxis')}
aria-label={t('parameters.seamlessXAxis')}
isChecked={seamlessXAxis}
onChange={handleChange}
/>
);
};
export default memo(ParamSeamlessXAxis);

View File

@ -0,0 +1,43 @@
import { useTranslation } from 'react-i18next';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { ChangeEvent, memo, useCallback } from 'react';
import { createSelector } from '@reduxjs/toolkit';
import { generationSelector } from 'features/parameters/store/generationSelectors';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAISwitch from 'common/components/IAISwitch';
import { setSeamlessYAxis } from 'features/parameters/store/generationSlice';
const selector = createSelector(
generationSelector,
(generation) => {
const { seamlessYAxis } = generation;
return { seamlessYAxis };
},
defaultSelectorOptions
);
const ParamSeamlessYAxis = () => {
const { t } = useTranslation();
const { seamlessYAxis } = useAppSelector(selector);
const dispatch = useAppDispatch();
const handleChange = useCallback(
(e: ChangeEvent<HTMLInputElement>) => {
dispatch(setSeamlessYAxis(e.target.checked));
},
[dispatch]
);
return (
<IAISwitch
label={t('parameters.seamlessYAxis')}
aria-label={t('parameters.seamlessYAxis')}
isChecked={seamlessYAxis}
onChange={handleChange}
/>
);
};
export default memo(ParamSeamlessYAxis);

View File

@ -1,13 +1,14 @@
import { HStack } from '@chakra-ui/react'; import { Flex, HStack } from '@chakra-ui/react';
import { NUMPY_RAND_MAX, NUMPY_RAND_MIN } from 'app/constants'; import { NUMPY_RAND_MAX, NUMPY_RAND_MIN } from 'app/constants';
import { RootState } from 'app/store/store'; import { RootState } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAINumberInput from 'common/components/IAINumberInput'; import IAINumberInput from 'common/components/IAINumberInput';
import { setSeed } from 'features/parameters/store/generationSlice'; import { setSeed } from 'features/parameters/store/generationSlice';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import ShuffleSeed from './ShuffleSeed'; import ParamSeedShuffle from './ParamSeedShuffle';
import ParamSeedRandomize from './ParamSeedRandomize';
export default function Seed() { export default function ParamSeed() {
const seed = useAppSelector((state: RootState) => state.generation.seed); const seed = useAppSelector((state: RootState) => state.generation.seed);
const shouldRandomizeSeed = useAppSelector( const shouldRandomizeSeed = useAppSelector(
(state: RootState) => state.generation.shouldRandomizeSeed (state: RootState) => state.generation.shouldRandomizeSeed
@ -23,25 +24,22 @@ export default function Seed() {
const handleChangeSeed = (v: number) => dispatch(setSeed(v)); const handleChangeSeed = (v: number) => dispatch(setSeed(v));
return ( return (
<HStack gap={2}> <IAINumberInput
<IAINumberInput label={t('parameters.seed')}
label={t('parameters.seed')} step={1}
step={1} precision={0}
precision={0} flexGrow={1}
flexGrow={1} min={NUMPY_RAND_MIN}
min={NUMPY_RAND_MIN} max={NUMPY_RAND_MAX}
max={NUMPY_RAND_MAX} isDisabled={shouldRandomizeSeed}
isDisabled={shouldRandomizeSeed} isInvalid={seed < 0 && shouldGenerateVariations}
isInvalid={seed < 0 && shouldGenerateVariations} onChange={handleChangeSeed}
onChange={handleChangeSeed} value={seed}
value={seed} formControlProps={{
formControlProps={{ display: 'flex',
display: 'flex', alignItems: 'center',
alignItems: 'center', gap: 3, // really this should work with 2 but seems to need to be 3 to match gap 2?
gap: 3, // really this should work with 2 but seems to need to be 3 to match gap 2? }}
}} />
/>
<ShuffleSeed />
</HStack>
); );
} }

View File

@ -0,0 +1,48 @@
import { Flex } from '@chakra-ui/react';
import ParamSeed from './ParamSeed';
import { memo, useCallback } from 'react';
import ParamSeedShuffle from './ParamSeedShuffle';
import { useTranslation } from 'react-i18next';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { createSelector } from '@reduxjs/toolkit';
import { generationSelector } from 'features/parameters/store/generationSelectors';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import { setShouldRandomizeSeed } from 'features/parameters/store/generationSlice';
import IAICollapse from 'common/components/IAICollapse';
const selector = createSelector(
generationSelector,
(generation) => {
const { shouldRandomizeSeed } = generation;
return { shouldRandomizeSeed };
},
defaultSelectorOptions
);
const ParamSeedSettings = () => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const { shouldRandomizeSeed } = useAppSelector(selector);
const handleToggle = useCallback(
() => dispatch(setShouldRandomizeSeed(!shouldRandomizeSeed)),
[dispatch, shouldRandomizeSeed]
);
return (
<IAICollapse
label={t('parameters.seed')}
isOpen={!shouldRandomizeSeed}
onToggle={handleToggle}
withSwitch
>
<Flex sx={{ gap: 4 }}>
<ParamSeed />
<ParamSeedShuffle />
</Flex>
</IAICollapse>
);
};
export default memo(ParamSeedSettings);

View File

@ -5,7 +5,7 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAISwitch from 'common/components/IAISwitch'; import IAISwitch from 'common/components/IAISwitch';
import { setShouldRandomizeSeed } from 'features/parameters/store/generationSlice'; import { setShouldRandomizeSeed } from 'features/parameters/store/generationSlice';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Switch } from '@chakra-ui/react'; import { FormControl, FormLabel, Switch } from '@chakra-ui/react';
// export default function RandomizeSeed() { // export default function RandomizeSeed() {
// const dispatch = useAppDispatch(); // const dispatch = useAppDispatch();
@ -27,7 +27,7 @@ import { Switch } from '@chakra-ui/react';
// ); // );
// } // }
const SeedToggle = () => { const ParamSeedRandomize = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { t } = useTranslation(); const { t } = useTranslation();
@ -36,15 +36,33 @@ const SeedToggle = () => {
); );
const handleChangeShouldRandomizeSeed = (e: ChangeEvent<HTMLInputElement>) => const handleChangeShouldRandomizeSeed = (e: ChangeEvent<HTMLInputElement>) =>
dispatch(setShouldRandomizeSeed(!e.target.checked)); dispatch(setShouldRandomizeSeed(e.target.checked));
return ( return (
<Switch <FormControl
aria-label={t('parameters.randomizeSeed')} sx={{
isChecked={!shouldRandomizeSeed} display: 'flex',
onChange={handleChangeShouldRandomizeSeed} gap: 4,
/> alignItems: 'center',
}}
>
<FormLabel
sx={{
mb: 0,
flexGrow: 1,
fontSize: 'sm',
fontWeight: 600,
color: 'base.100',
}}
>
{t('parameters.randomizeSeed')}
</FormLabel>
<Switch
isChecked={shouldRandomizeSeed}
onChange={handleChangeShouldRandomizeSeed}
/>
</FormControl>
); );
}; };
export default memo(SeedToggle); export default memo(ParamSeedRandomize);

View File

@ -1,14 +1,15 @@
import { Button } from '@chakra-ui/react'; import { Box } from '@chakra-ui/react';
import { NUMPY_RAND_MAX, NUMPY_RAND_MIN } from 'app/constants'; import { NUMPY_RAND_MAX, NUMPY_RAND_MIN } from 'app/constants';
import { RootState } from 'app/store/store'; import { RootState } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAIButton from 'common/components/IAIButton';
import IAIIconButton from 'common/components/IAIIconButton'; import IAIIconButton from 'common/components/IAIIconButton';
import randomInt from 'common/util/randomInt'; import randomInt from 'common/util/randomInt';
import { setSeed } from 'features/parameters/store/generationSlice'; import { setSeed } from 'features/parameters/store/generationSlice';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { FaRandom } from 'react-icons/fa'; import { FaRandom } from 'react-icons/fa';
export default function ShuffleSeed() { export default function ParamSeedShuffle() {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const shouldRandomizeSeed = useAppSelector( const shouldRandomizeSeed = useAppSelector(
(state: RootState) => state.generation.shouldRandomizeSeed (state: RootState) => state.generation.shouldRandomizeSeed
@ -19,20 +20,14 @@ export default function ShuffleSeed() {
dispatch(setSeed(randomInt(NUMPY_RAND_MIN, NUMPY_RAND_MAX))); dispatch(setSeed(randomInt(NUMPY_RAND_MIN, NUMPY_RAND_MAX)));
return ( return (
<IAIIconButton <IAIButton
size="sm" size="sm"
isDisabled={shouldRandomizeSeed} isDisabled={shouldRandomizeSeed}
aria-label={t('parameters.shuffle')} aria-label={t('parameters.shuffle')}
tooltip={t('parameters.shuffle')} tooltip={t('parameters.shuffle')}
icon={<FaRandom />}
onClick={handleClickRandomizeSeed} onClick={handleClickRandomizeSeed}
/> >
// <Button <Box px={2}> {t('parameters.shuffle')}</Box>
// size="sm" </IAIButton>
// onClick={handleClickRandomizeSeed}
// padding="0 1.5rem"
// >
// <p>{t('parameters.shuffle')}</p>
// </Button>
); );
} }

View File

@ -0,0 +1,37 @@
import { memo } from 'react';
import { Flex } from '@chakra-ui/react';
import ParamSymmetryHorizontal from './ParamSymmetryHorizontal';
import ParamSymmetryVertical from './ParamSymmetryVertical';
import { useTranslation } from 'react-i18next';
import IAICollapse from 'common/components/IAICollapse';
import { RootState } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { setShouldUseSymmetry } from 'features/parameters/store/generationSlice';
const ParamSymmetryCollapse = () => {
const { t } = useTranslation();
const shouldUseSymmetry = useAppSelector(
(state: RootState) => state.generation.shouldUseSymmetry
);
const dispatch = useAppDispatch();
const handleToggle = () => dispatch(setShouldUseSymmetry(!shouldUseSymmetry));
return (
<IAICollapse
label={t('parameters.symmetry')}
isOpen={shouldUseSymmetry}
onToggle={handleToggle}
withSwitch
>
<Flex sx={{ gap: 2, flexDirection: 'column' }}>
<ParamSymmetryHorizontal />
<ParamSymmetryVertical />
</Flex>
</IAICollapse>
);
};
export default memo(ParamSymmetryCollapse);

View File

@ -0,0 +1,32 @@
import { RootState } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAISlider from 'common/components/IAISlider';
import { setHorizontalSymmetrySteps } from 'features/parameters/store/generationSlice';
import { useTranslation } from 'react-i18next';
export default function ParamSymmetryHorizontal() {
const horizontalSymmetrySteps = useAppSelector(
(state: RootState) => state.generation.horizontalSymmetrySteps
);
const steps = useAppSelector((state: RootState) => state.generation.steps);
const dispatch = useAppDispatch();
const { t } = useTranslation();
return (
<IAISlider
label={t('parameters.hSymmetryStep')}
value={horizontalSymmetrySteps}
onChange={(v) => dispatch(setHorizontalSymmetrySteps(v))}
min={0}
max={steps}
step={1}
withInput
withSliderMarks
withReset
handleReset={() => dispatch(setHorizontalSymmetrySteps(0))}
/>
);
}

View File

@ -3,7 +3,7 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAISwitch from 'common/components/IAISwitch'; import IAISwitch from 'common/components/IAISwitch';
import { setShouldUseSymmetry } from 'features/parameters/store/generationSlice'; import { setShouldUseSymmetry } from 'features/parameters/store/generationSlice';
export default function SymmetryToggle() { export default function ParamSymmetryToggle() {
const shouldUseSymmetry = useAppSelector( const shouldUseSymmetry = useAppSelector(
(state: RootState) => state.generation.shouldUseSymmetry (state: RootState) => state.generation.shouldUseSymmetry
); );

View File

@ -0,0 +1,32 @@
import { RootState } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAISlider from 'common/components/IAISlider';
import { setVerticalSymmetrySteps } from 'features/parameters/store/generationSlice';
import { useTranslation } from 'react-i18next';
export default function ParamSymmetryVertical() {
const verticalSymmetrySteps = useAppSelector(
(state: RootState) => state.generation.verticalSymmetrySteps
);
const steps = useAppSelector((state: RootState) => state.generation.steps);
const dispatch = useAppDispatch();
const { t } = useTranslation();
return (
<IAISlider
label={t('parameters.vSymmetryStep')}
value={verticalSymmetrySteps}
onChange={(v) => dispatch(setVerticalSymmetrySteps(v))}
min={0}
max={steps}
step={1}
withInput
withSliderMarks
withReset
handleReset={() => dispatch(setVerticalSymmetrySteps(0))}
/>
);
}

View File

@ -4,7 +4,7 @@ import IAISlider from 'common/components/IAISlider';
import { setVariationAmount } from 'features/parameters/store/generationSlice'; import { setVariationAmount } from 'features/parameters/store/generationSlice';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
export default function VariationAmount() { export default function ParamVariationAmount() {
const variationAmount = useAppSelector( const variationAmount = useAppSelector(
(state: RootState) => state.generation.variationAmount (state: RootState) => state.generation.variationAmount
); );

View File

@ -0,0 +1,37 @@
import ParamVariationWeights from './ParamVariationWeights';
import ParamVariationAmount from './ParamVariationAmount';
import { useTranslation } from 'react-i18next';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { RootState } from 'app/store/store';
import { setShouldGenerateVariations } from 'features/parameters/store/generationSlice';
import { Flex } from '@chakra-ui/react';
import IAICollapse from 'common/components/IAICollapse';
import { memo } from 'react';
const ParamVariationCollapse = () => {
const { t } = useTranslation();
const shouldGenerateVariations = useAppSelector(
(state: RootState) => state.generation.shouldGenerateVariations
);
const dispatch = useAppDispatch();
const handleToggle = () =>
dispatch(setShouldGenerateVariations(!shouldGenerateVariations));
return (
<IAICollapse
label={t('parameters.variations')}
isOpen={shouldGenerateVariations}
onToggle={handleToggle}
withSwitch
>
<Flex sx={{ gap: 2, flexDirection: 'column' }}>
<ParamVariationAmount />
<ParamVariationWeights />
</Flex>
</IAICollapse>
);
};
export default memo(ParamVariationCollapse);

View File

@ -6,7 +6,7 @@ import { setSeedWeights } from 'features/parameters/store/generationSlice';
import { ChangeEvent } from 'react'; import { ChangeEvent } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
export default function SeedWeights() { export default function ParamVariationWeights() {
const seedWeights = useAppSelector( const seedWeights = useAppSelector(
(state: RootState) => state.generation.seedWeights (state: RootState) => state.generation.seedWeights
); );

View File

@ -20,7 +20,6 @@ export interface GenerationState {
negativePrompt: string; negativePrompt: string;
sampler: string; sampler: string;
seamBlur: number; seamBlur: number;
seamless: boolean;
seamSize: number; seamSize: number;
seamSteps: number; seamSteps: number;
seamStrength: number; seamStrength: number;
@ -29,6 +28,7 @@ export interface GenerationState {
shouldFitToWidthHeight: boolean; shouldFitToWidthHeight: boolean;
shouldGenerateVariations: boolean; shouldGenerateVariations: boolean;
shouldRandomizeSeed: boolean; shouldRandomizeSeed: boolean;
shouldUseNoiseSettings: boolean;
steps: number; steps: number;
threshold: number; threshold: number;
tileSize: number; tileSize: number;
@ -39,6 +39,9 @@ export interface GenerationState {
verticalSymmetrySteps: number; verticalSymmetrySteps: number;
isImageToImageEnabled: boolean; isImageToImageEnabled: boolean;
model: string; model: string;
shouldUseSeamless: boolean;
seamlessXAxis: boolean;
seamlessYAxis: boolean;
} }
export const initialGenerationState: GenerationState = { export const initialGenerationState: GenerationState = {
@ -53,7 +56,6 @@ export const initialGenerationState: GenerationState = {
negativePrompt: '', negativePrompt: '',
sampler: 'k_lms', sampler: 'k_lms',
seamBlur: 16, seamBlur: 16,
seamless: false,
seamSize: 96, seamSize: 96,
seamSteps: 30, seamSteps: 30,
seamStrength: 0.7, seamStrength: 0.7,
@ -62,6 +64,7 @@ export const initialGenerationState: GenerationState = {
shouldFitToWidthHeight: true, shouldFitToWidthHeight: true,
shouldGenerateVariations: false, shouldGenerateVariations: false,
shouldRandomizeSeed: true, shouldRandomizeSeed: true,
shouldUseNoiseSettings: false,
steps: 50, steps: 50,
threshold: 0, threshold: 0,
tileSize: 32, tileSize: 32,
@ -72,6 +75,9 @@ export const initialGenerationState: GenerationState = {
verticalSymmetrySteps: 0, verticalSymmetrySteps: 0,
isImageToImageEnabled: false, isImageToImageEnabled: false,
model: '', model: '',
shouldUseSeamless: false,
seamlessXAxis: true,
seamlessYAxis: true,
}; };
const initialState: GenerationState = initialGenerationState; const initialState: GenerationState = initialGenerationState;
@ -146,7 +152,13 @@ export const generationSlice = createSlice({
state.maskPath = action.payload; state.maskPath = action.payload;
}, },
setSeamless: (state, action: PayloadAction<boolean>) => { setSeamless: (state, action: PayloadAction<boolean>) => {
state.seamless = action.payload; state.shouldUseSeamless = action.payload;
},
setSeamlessXAxis: (state, action: PayloadAction<boolean>) => {
state.seamlessXAxis = action.payload;
},
setSeamlessYAxis: (state, action: PayloadAction<boolean>) => {
state.seamlessYAxis = action.payload;
}, },
setShouldFitToWidthHeight: (state, action: PayloadAction<boolean>) => { setShouldFitToWidthHeight: (state, action: PayloadAction<boolean>) => {
state.shouldFitToWidthHeight = action.payload; state.shouldFitToWidthHeight = action.payload;
@ -348,6 +360,9 @@ export const generationSlice = createSlice({
setVerticalSymmetrySteps: (state, action: PayloadAction<number>) => { setVerticalSymmetrySteps: (state, action: PayloadAction<number>) => {
state.verticalSymmetrySteps = action.payload; state.verticalSymmetrySteps = action.payload;
}, },
setShouldUseNoiseSettings: (state, action: PayloadAction<boolean>) => {
state.shouldUseNoiseSettings = action.payload;
},
initialImageChanged: (state, action: PayloadAction<InvokeAI.Image>) => { initialImageChanged: (state, action: PayloadAction<InvokeAI.Image>) => {
state.initialImage = action.payload; state.initialImage = action.payload;
state.isImageToImageEnabled = true; state.isImageToImageEnabled = true;
@ -382,7 +397,6 @@ export const {
setNegativePrompt, setNegativePrompt,
setSampler, setSampler,
setSeamBlur, setSeamBlur,
setSeamless,
setSeamSize, setSeamSize,
setSeamSteps, setSeamSteps,
setSeamStrength, setSeamStrength,
@ -402,6 +416,10 @@ export const {
initialImageChanged, initialImageChanged,
isImageToImageEnabledChanged, isImageToImageEnabledChanged,
modelSelected, modelSelected,
setShouldUseNoiseSettings,
setSeamless,
setSeamlessXAxis,
setSeamlessYAxis,
} = generationSlice.actions; } = generationSlice.actions;
export default generationSlice.reducer; export default generationSlice.reducer;

View File

@ -0,0 +1,98 @@
import type { PayloadAction } from '@reduxjs/toolkit';
import { createSlice } from '@reduxjs/toolkit';
import { FACETOOL_TYPES } from 'app/constants';
export interface HiresState {
codeformerFidelity: number;
facetoolStrength: number;
facetoolType: FacetoolType;
hiresFix: boolean;
hiresStrength: number;
shouldLoopback: boolean;
shouldRunESRGAN: boolean;
shouldRunFacetool: boolean;
upscalingLevel: UpscalingLevel;
upscalingDenoising: number;
upscalingStrength: number;
}
export const initialHiresState: HiresState = {
codeformerFidelity: 0.75,
facetoolStrength: 0.75,
facetoolType: 'gfpgan',
hiresFix: false,
hiresStrength: 0.75,
hiresSteps: 30,
hiresWidth: 512,
hiresHeight: 512,
hiresModel: '',
shouldLoopback: false,
shouldRunESRGAN: false,
shouldRunFacetool: false,
upscalingLevel: 4,
upscalingDenoising: 0.75,
upscalingStrength: 0.75,
};
export const postprocessingSlice = createSlice({
name: 'postprocessing',
initialState: initialPostprocessingState,
reducers: {
setFacetoolStrength: (state, action: PayloadAction<number>) => {
state.facetoolStrength = action.payload;
},
setCodeformerFidelity: (state, action: PayloadAction<number>) => {
state.codeformerFidelity = action.payload;
},
setUpscalingLevel: (state, action: PayloadAction<UpscalingLevel>) => {
state.upscalingLevel = action.payload;
},
setUpscalingDenoising: (state, action: PayloadAction<number>) => {
state.upscalingDenoising = action.payload;
},
setUpscalingStrength: (state, action: PayloadAction<number>) => {
state.upscalingStrength = action.payload;
},
setHiresFix: (state, action: PayloadAction<boolean>) => {
state.hiresFix = action.payload;
},
setHiresStrength: (state, action: PayloadAction<number>) => {
state.hiresStrength = action.payload;
},
resetPostprocessingState: (state) => {
return {
...state,
...initialPostprocessingState,
};
},
setShouldRunFacetool: (state, action: PayloadAction<boolean>) => {
state.shouldRunFacetool = action.payload;
},
setFacetoolType: (state, action: PayloadAction<FacetoolType>) => {
state.facetoolType = action.payload;
},
setShouldRunESRGAN: (state, action: PayloadAction<boolean>) => {
state.shouldRunESRGAN = action.payload;
},
setShouldLoopback: (state, action: PayloadAction<boolean>) => {
state.shouldLoopback = action.payload;
},
},
});
export const {
resetPostprocessingState,
setCodeformerFidelity,
setFacetoolStrength,
setFacetoolType,
setHiresFix,
setHiresStrength,
setShouldLoopback,
setShouldRunESRGAN,
setShouldRunFacetool,
setUpscalingLevel,
setUpscalingDenoising,
setUpscalingStrength,
} = postprocessingSlice.actions;
export default postprocessingSlice.reducer;

View File

@ -1,6 +1,6 @@
import { isEqual } from 'lodash-es'; import { isEqual } from 'lodash-es';
import ResizableDrawer from './common/ResizableDrawer/ResizableDrawer'; import ResizableDrawer from './common/ResizableDrawer/ResizableDrawer';
import CreateBaseSettings from './tabs/Create/CreateBaseSettings'; import TextTabParameters from './tabs/text/TextTabParameters';
import { createSelector } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
import { activeTabNameSelector, uiSelector } from '../store/uiSelectors'; import { activeTabNameSelector, uiSelector } from '../store/uiSelectors';
import { lightboxSelector } from 'features/lightbox/store/lightboxSelectors'; import { lightboxSelector } from 'features/lightbox/store/lightboxSelectors';
@ -14,10 +14,10 @@ import { Flex } from '@chakra-ui/react';
import InvokeAILogoComponent from 'features/system/components/InvokeAILogoComponent'; import InvokeAILogoComponent from 'features/system/components/InvokeAILogoComponent';
import PinParametersPanelButton from './PinParametersPanelButton'; import PinParametersPanelButton from './PinParametersPanelButton';
import { Panel, PanelGroup } from 'react-resizable-panels'; import { Panel, PanelGroup } from 'react-resizable-panels';
import CreateSidePanelPinned from './tabs/Create/CreateSidePanelPinned'; import CreateSidePanelPinned from './tabs/text/TextTabSettingsPinned';
import CreateTextParameters from './tabs/Create/CreateBaseSettings'; import CreateTextParameters from './tabs/text/TextTabParameters';
import ResizeHandle from './tabs/ResizeHandle'; import ResizeHandle from './tabs/ResizeHandle';
import CreateImageSettings from './tabs/Create/CreateImageSettings'; import CreateImageSettings from './tabs/image/ImageTabSettings';
const selector = createSelector( const selector = createSelector(
[uiSelector, activeTabNameSelector, lightboxSelector], [uiSelector, activeTabNameSelector, lightboxSelector],

View File

@ -40,7 +40,7 @@ export const floatingParametersPanelButtonSelector = createSelector(
const shouldShowParametersPanelButton = const shouldShowParametersPanelButton =
!canvasBetaLayoutCheck && !canvasBetaLayoutCheck &&
!shouldShowParametersPanel && !shouldShowParametersPanel &&
['generate', 'unifiedCanvas'].includes(activeTabName); ['text', 'image', 'unifiedCanvas'].includes(activeTabName);
return { return {
shouldPinParametersPanel, shouldPinParametersPanel,

View File

@ -26,31 +26,34 @@ import {
} from 'react'; } from 'react';
import { useHotkeys } from 'react-hotkeys-hook'; import { useHotkeys } from 'react-hotkeys-hook';
import { MdDeviceHub, MdGridOn } from 'react-icons/md'; import { MdDeviceHub, MdGridOn } from 'react-icons/md';
import { GoTextSize } from 'react-icons/go';
import { activeTabIndexSelector } from '../store/uiSelectors'; import { activeTabIndexSelector } from '../store/uiSelectors';
import UnifiedCanvasWorkarea from 'features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasWorkarea'; import UnifiedCanvasWorkarea from 'features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasWorkarea';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { ResourceKey } from 'i18next'; import { ResourceKey } from 'i18next';
import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale'; import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale';
import NodeEditor from 'features/nodes/components/NodeEditor'; import NodeEditor from 'features/nodes/components/NodeEditor';
import GenerateWorkspace from './tabs/Create/GenerateWorkspace'; import GenerateWorkspace from './tabs/text/GenerateWorkspace';
import { createSelector } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
import { BsLightningChargeFill } from 'react-icons/bs'; import { BsLightningChargeFill } from 'react-icons/bs';
import { configSelector } from 'features/system/store/configSelectors'; import { configSelector } from 'features/system/store/configSelectors';
import { isEqual } from 'lodash-es'; import { isEqual } from 'lodash-es';
import AnimatedImageToImagePanel from 'features/parameters/components/AnimatedImageToImagePanel'; import AnimatedImageToImagePanel from 'features/parameters/components/AnimatedImageToImagePanel';
import Scrollable from './common/Scrollable'; import Scrollable from './common/Scrollable';
import CreateBaseSettings from './tabs/Create/CreateBaseSettings'; import TextTabParameters from './tabs/text/TextTabParameters';
import PinParametersPanelButton from './PinParametersPanelButton'; import PinParametersPanelButton from './PinParametersPanelButton';
import ParametersSlide from './common/ParametersSlide'; import ParametersSlide from './common/ParametersSlide';
import ImageGalleryPanel from 'features/gallery/components/ImageGalleryPanel'; import ImageGalleryPanel from 'features/gallery/components/ImageGalleryPanel';
import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels'; import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels';
import ImageGalleryContent from 'features/gallery/components/ImageGalleryContent'; import ImageGalleryContent from 'features/gallery/components/ImageGalleryContent';
import CreateTabContent from './tabs/Create/CreateContent'; import TextTabMain from './tabs/text/TextTabMain';
import ParametersPanel from './ParametersPanel'; import ParametersPanel from './ParametersPanel';
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react'; import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
import CreateTab from './tabs/Create/CreateTab'; import TextTab from './tabs/text/TextTab';
import UnifiedCanvasTab from './tabs/UnifiedCanvas/UnifiedCanvasTab'; import UnifiedCanvasTab from './tabs/UnifiedCanvas/UnifiedCanvasTab';
import NodesTab from './tabs/Nodes/NodesTab'; import NodesTab from './tabs/Nodes/NodesTab';
import { FaImage } from 'react-icons/fa';
import ResizeHandle from './tabs/ResizeHandle';
export interface InvokeTabInfo { export interface InvokeTabInfo {
id: InvokeTabName; id: InvokeTabName;
@ -60,9 +63,14 @@ export interface InvokeTabInfo {
const tabs: InvokeTabInfo[] = [ const tabs: InvokeTabInfo[] = [
{ {
id: 'generate', id: 'text',
icon: <Icon as={BsLightningChargeFill} sx={{ boxSize: 5 }} />, icon: <Icon as={GoTextSize} sx={{ boxSize: 5 }} />,
content: <CreateTab />, content: <TextTab />,
},
{
id: 'image',
icon: <Icon as={FaImage} sx={{ boxSize: 5 }} />,
content: <TextTab />,
}, },
{ {
id: 'unifiedCanvas', id: 'unifiedCanvas',
@ -107,14 +115,18 @@ const InvokeTabs = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
useHotkeys('1', () => { useHotkeys('1', () => {
dispatch(setActiveTab('generate')); dispatch(setActiveTab('text'));
}); });
useHotkeys('2', () => { useHotkeys('2', () => {
dispatch(setActiveTab('unifiedCanvas')); dispatch(setActiveTab('image'));
}); });
useHotkeys('3', () => { useHotkeys('3', () => {
dispatch(setActiveTab('unifiedCanvas'));
});
useHotkeys('4', () => {
dispatch(setActiveTab('nodes')); dispatch(setActiveTab('nodes'));
}); });
@ -183,23 +195,27 @@ const InvokeTabs = () => {
> >
{tabs} {tabs}
</TabList> </TabList>
<TabPanels>{tabPanels}</TabPanels> <PanelGroup
autoSaveId="app"
direction="horizontal"
style={{ height: '100%', width: '100%' }}
>
<Panel id="tabContent">
<TabPanels style={{ height: '100%', width: '100%' }}>
{tabPanels}
</TabPanels>
</Panel>
{shouldPinGallery && shouldShowGallery && (
<>
<ResizeHandle />
<Panel id="gallery" order={3} defaultSize={10} minSize={10}>
<ImageGalleryContent />
</Panel>
</>
)}
</PanelGroup>
</Tabs> </Tabs>
); );
}; };
export default memo(InvokeTabs); export default memo(InvokeTabs);
// <PanelGroup autoSaveId="example" direction="horizontal">
// <Panel defaultSize={25}>
// <SourcesExplorer />
// </Panel>
// <PanelResizeHandle />
// <Panel>
// <SourceViewer />
// </Panel>
// <PanelResizeHandle />
// <Panel defaultSize={25}>
// <Console />
// </Panel>
// </PanelGroup>;

View File

@ -1,123 +0,0 @@
import {
AspectRatio,
Box,
Flex,
Select,
Slider,
SliderFilledTrack,
SliderThumb,
SliderTrack,
Text,
} from '@chakra-ui/react';
import { Feature } from 'app/features';
import IAISlider from 'common/components/IAISlider';
import IAISwitch from 'common/components/IAISwitch';
import ImageToImageSettings from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageSettings';
import ImageToImageToggle from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageToggle';
import OutputSettings from 'features/parameters/components/AdvancedParameters/Output/OutputSettings';
import SymmetrySettings from 'features/parameters/components/AdvancedParameters/Output/SymmetrySettings';
import SymmetryToggle from 'features/parameters/components/AdvancedParameters/Output/SymmetryToggle';
import RandomizeSeed from 'features/parameters/components/AdvancedParameters/Seed/RandomizeSeed';
import SeedSettings from 'features/parameters/components/AdvancedParameters/Seed/SeedSettings';
import GenerateVariationsToggle from 'features/parameters/components/AdvancedParameters/Variations/GenerateVariations';
import VariationsSettings from 'features/parameters/components/AdvancedParameters/Variations/VariationsSettings';
import DimensionsSettings from 'features/parameters/components/ImageDimensions/DimensionsSettings';
import MainSettings from 'features/parameters/components/MainParameters/MainSettings';
import ParametersAccordion, {
ParametersAccordionItems,
} from 'features/parameters/components/ParametersAccordion';
import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons';
import NegativePromptInput from 'features/parameters/components/PromptInput/NegativePromptInput';
import PromptInput from 'features/parameters/components/PromptInput/PromptInput';
import { findIndex } from 'lodash-es';
import {
OverlayScrollbarsComponent,
useOverlayScrollbars,
} from 'overlayscrollbars-react';
import { memo, useMemo, useState, useRef, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { PARAMETERS_PANEL_WIDTH } from 'theme/util/constants';
import OverlayScrollable from '../../common/OverlayScrollable';
import AnimatedImageToImagePanel from 'features/parameters/components/AnimatedImageToImagePanel';
const CreateBaseSettings = () => {
const { t } = useTranslation();
const generateAccordionItems: ParametersAccordionItems = useMemo(
() => ({
// general: {
// name: 'general',
// header: `${t('parameters.general')}`,
// feature: undefined,
// content: <MainSettings />,
// },
seed: {
name: 'seed',
header: `${t('parameters.seed')}`,
feature: Feature.SEED,
content: <SeedSettings />,
additionalHeaderComponents: <RandomizeSeed />,
},
// imageToImage: {
// name: 'imageToImage',
// header: `${t('parameters.imageToImage')}`,
// feature: undefined,
// content: <ImageToImageSettings />,
// additionalHeaderComponents: <ImageToImageToggle />,
// },
variations: {
name: 'variations',
header: `${t('parameters.variations')}`,
feature: Feature.VARIATIONS,
content: <VariationsSettings />,
additionalHeaderComponents: <GenerateVariationsToggle />,
},
symmetry: {
name: 'symmetry',
header: `${t('parameters.symmetry')}`,
content: <SymmetrySettings />,
additionalHeaderComponents: <SymmetryToggle />,
},
other: {
name: 'other',
header: `${t('parameters.otherOptions')}`,
feature: Feature.OTHER,
content: <OutputSettings />,
},
}),
[t]
);
return (
<OverlayScrollable>
<Flex
sx={{
gap: 2,
flexDirection: 'column',
h: 'full',
w: 'full',
position: 'absolute',
}}
>
<PromptInput />
<NegativePromptInput />
<ProcessButtons />
<ImageToImageToggle />
<Flex
sx={{
flexDirection: 'column',
gap: 2,
bg: 'base.800',
p: 4,
borderRadius: 'base',
}}
>
<MainSettings />
</Flex>
<ParametersAccordion accordionItems={generateAccordionItems} />
</Flex>
</OverlayScrollable>
);
};
export default memo(CreateBaseSettings);

View File

@ -1,55 +0,0 @@
import { Box, Flex } from '@chakra-ui/react';
import { useAppSelector } from 'app/store/storeHooks';
import { memo } from 'react';
import CreateTabContent from './CreateContent';
import CreateBaseSettings from './CreateBaseSettings';
import PinParametersPanelButton from '../../PinParametersPanelButton';
import { RootState } from 'app/store/store';
import Scrollable from '../../common/Scrollable';
import ParametersSlide from '../../common/ParametersSlide';
import AnimatedImageToImagePanel from 'features/parameters/components/AnimatedImageToImagePanel';
const GenerateWorkspace = () => {
const shouldPinParametersPanel = useAppSelector(
(state: RootState) => state.ui.shouldPinParametersPanel
);
return <CreateTabContent />;
return (
<Flex
flexDirection={{ base: 'column-reverse', xl: 'row' }}
w="full"
h="full"
gap={4}
>
{shouldPinParametersPanel ? (
<Flex sx={{ flexDirection: 'row-reverse' }}>
<AnimatedImageToImagePanel />
<Flex
sx={{
flexDirection: 'column',
width: '28rem',
flexShrink: 0,
position: 'relative',
}}
>
<Scrollable>
<CreateBaseSettings />
</Scrollable>
<PinParametersPanelButton
sx={{ position: 'absolute', top: 0, insetInlineEnd: 0 }}
/>
</Flex>
</Flex>
) : (
<ParametersSlide>
<CreateBaseSettings />
</ParametersSlide>
)}
<CreateTabContent />
</Flex>
);
};
export default memo(GenerateWorkspace);

View File

@ -2,13 +2,40 @@ import { Box, Flex } from '@chakra-ui/react';
import { memo } from 'react'; import { memo } from 'react';
import { PanelResizeHandle } from 'react-resizable-panels'; import { PanelResizeHandle } from 'react-resizable-panels';
const ResizeHandle = () => { type ResizeHandleProps = {
direction?: 'horizontal' | 'vertical';
};
const ResizeHandle = (props: ResizeHandleProps) => {
const { direction = 'horizontal' } = props;
if (direction === 'horizontal') {
return (
<PanelResizeHandle>
<Flex
sx={{
w: 6,
h: 'full',
justifyContent: 'center',
alignItems: 'center',
}}
>
<Box sx={{ w: 0.5, h: 'calc(100% - 4px)', bg: 'base.850' }} />
</Flex>
</PanelResizeHandle>
);
}
return ( return (
<PanelResizeHandle> <PanelResizeHandle>
<Flex <Flex
sx={{ w: 6, h: 'full', justifyContent: 'center', alignItems: 'center' }} sx={{
w: 'full',
h: 6,
justifyContent: 'center',
alignItems: 'center',
}}
> >
<Box sx={{ w: 0.5, h: 'calc(100% - 4px)', bg: 'base.850' }} /> <Box sx={{ w: 'calc(100% - 4px)', h: 0.5, bg: 'base.850' }} />
</Flex> </Flex>
</PanelResizeHandle> </PanelResizeHandle>
); );

View File

@ -4,20 +4,23 @@ import BoundingBoxSettings from 'features/parameters/components/AdvancedParamete
import InfillAndScalingSettings from 'features/parameters/components/AdvancedParameters/Canvas/InfillAndScalingSettings'; import InfillAndScalingSettings from 'features/parameters/components/AdvancedParameters/Canvas/InfillAndScalingSettings';
import SeamCorrectionSettings from 'features/parameters/components/AdvancedParameters/Canvas/SeamCorrection/SeamCorrectionSettings'; import SeamCorrectionSettings from 'features/parameters/components/AdvancedParameters/Canvas/SeamCorrection/SeamCorrectionSettings';
import ImageToImageStrength from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageStrength'; import ImageToImageStrength from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageStrength';
import SymmetrySettings from 'features/parameters/components/AdvancedParameters/Output/SymmetrySettings';
import SymmetryToggle from 'features/parameters/components/AdvancedParameters/Output/SymmetryToggle';
import SeedSettings from 'features/parameters/components/AdvancedParameters/Seed/SeedSettings';
import GenerateVariationsToggle from 'features/parameters/components/AdvancedParameters/Variations/GenerateVariations';
import VariationsSettings from 'features/parameters/components/AdvancedParameters/Variations/VariationsSettings';
import MainSettings from 'features/parameters/components/MainParameters/MainSettings'; import MainSettings from 'features/parameters/components/MainParameters/MainSettings';
import ParametersAccordion, { import ParametersAccordion, {
ParametersAccordionItems, ParametersAccordionItems,
} from 'features/parameters/components/ParametersAccordion'; } from 'features/parameters/components/ParametersAccordion';
import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons'; import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons';
import NegativePromptInput from 'features/parameters/components/PromptInput/NegativePromptInput';
import PromptInput from 'features/parameters/components/PromptInput/PromptInput';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import OverlayScrollable from '../../common/OverlayScrollable'; import OverlayScrollable from '../../common/OverlayScrollable';
// import ParamSeedSettings from 'features/parameters/components/Parameters/Seed/ParamSeedSettings';
// import ParamVariationSettings from 'features/parameters/components/Parameters/Variations/ParamVariationSettings';
// import ParamSymmetrySettings from 'features/parameters/components/Parameters/Symmetry/ParamSymmetrySettings';
// import ParamVariationToggle from 'features/parameters/components/Parameters/Variations/ParamVariationToggle';
// import ParamSymmetryToggle from 'features/parameters/components/Parameters/Symmetry/ParamSymmetryToggle';
import ParamPositiveConditioning from 'features/parameters/components/Parameters/ParamPositiveConditioning';
import ParamNegativeConditioning from 'features/parameters/components/Parameters/ParamNegativeConditioning';
import ParamSeedCollapse from 'features/parameters/components/Parameters/Seed/ParamSeedCollapse';
import ParamVariationCollapse from 'features/parameters/components/Parameters/Variations/ParamVariationCollapse';
import ParamSymmetryCollapse from 'features/parameters/components/Parameters/Symmetry/ParamSymmetryCollapse';
export default function UnifiedCanvasParameters() { export default function UnifiedCanvasParameters() {
const { t } = useTranslation(); const { t } = useTranslation();
@ -35,12 +38,12 @@ export default function UnifiedCanvasParameters() {
feature: undefined, feature: undefined,
content: <ImageToImageStrength />, content: <ImageToImageStrength />,
}, },
seed: { // seed: {
name: 'seed', // name: 'seed',
header: `${t('parameters.seed')}`, // header: `${t('parameters.seed')}`,
feature: Feature.SEED, // feature: Feature.SEED,
content: <SeedSettings />, // content: <ParamSeedSettings />,
}, // },
boundingBox: { boundingBox: {
name: 'boundingBox', name: 'boundingBox',
header: `${t('parameters.boundingBoxHeader')}`, header: `${t('parameters.boundingBoxHeader')}`,
@ -59,19 +62,19 @@ export default function UnifiedCanvasParameters() {
feature: Feature.INFILL_AND_SCALING, feature: Feature.INFILL_AND_SCALING,
content: <InfillAndScalingSettings />, content: <InfillAndScalingSettings />,
}, },
variations: { // variations: {
name: 'variations', // name: 'variations',
header: `${t('parameters.variations')}`, // header: `${t('parameters.variations')}`,
feature: Feature.VARIATIONS, // feature: Feature.VARIATIONS,
content: <VariationsSettings />, // content: <ParamVariationSettings />,
additionalHeaderComponents: <GenerateVariationsToggle />, // additionalHeaderComponents: <ParamVariationToggle />,
}, // },
symmetry: { // symmetry: {
name: 'symmetry', // name: 'symmetry',
header: `${t('parameters.symmetry')}`, // header: `${t('parameters.symmetry')}`,
content: <SymmetrySettings />, // content: <ParamSymmetrySettings />,
additionalHeaderComponents: <SymmetryToggle />, // additionalHeaderComponents: <ParamSymmetryToggle />,
}, // },
}; };
return ( return (
@ -85,9 +88,12 @@ export default function UnifiedCanvasParameters() {
position: 'absolute', position: 'absolute',
}} }}
> >
<PromptInput /> <ParamPositiveConditioning />
<NegativePromptInput /> <ParamNegativeConditioning />
<ProcessButtons /> <ProcessButtons />
<ParamSeedCollapse />
<ParamVariationCollapse />
<ParamSymmetryCollapse />
<ParametersAccordion accordionItems={unifiedCanvasAccordions} /> <ParametersAccordion accordionItems={unifiedCanvasAccordions} />
</Flex> </Flex>
</OverlayScrollable> </OverlayScrollable>

View File

@ -1,20 +1,12 @@
import { Portal, TabPanel } from '@chakra-ui/react'; import { Portal, TabPanel } from '@chakra-ui/react';
import { memo } from 'react'; import { memo } from 'react';
import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels'; import { Panel, PanelGroup } from 'react-resizable-panels';
import CreateBaseSettings from './CreateBaseSettings';
import PinParametersPanelButton from '../../PinParametersPanelButton'; import PinParametersPanelButton from '../../PinParametersPanelButton';
import ImageGalleryContent from 'features/gallery/components/ImageGalleryContent';
import { createSelector } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
import { uiSelector } from 'features/ui/store/uiSelectors'; import { uiSelector } from 'features/ui/store/uiSelectors';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale'; import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale';
import CreateTabContent from './CreateContent';
import ResizeHandle from '../ResizeHandle'; import ResizeHandle from '../ResizeHandle';
import AnimatedImageToImagePanel from 'features/parameters/components/AnimatedImageToImagePanel';
import ImageToImageSettings from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageSettings';
import CreateSidePanelPinned from './CreateSidePanelPinned';
import CreateTextParameters from './CreateBaseSettings';
import CreateImageSettings from './CreateImageSettings';
const selector = createSelector(uiSelector, (ui) => { const selector = createSelector(uiSelector, (ui) => {
const { const {
@ -34,7 +26,7 @@ const selector = createSelector(uiSelector, (ui) => {
}; };
}); });
const CreateTab = () => { const TextTab = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { const {
shouldPinGallery, shouldPinGallery,
@ -46,61 +38,39 @@ const CreateTab = () => {
return ( return (
<PanelGroup <PanelGroup
autoSaveId="createTab_pinned" autoSaveId="textTab"
direction="horizontal" direction="horizontal"
style={{ height: '100%', width: '100%' }} style={{ height: '100%', width: '100%' }}
> >
{shouldPinParametersPanel && shouldShowParametersPanel && ( {shouldPinParametersPanel && shouldShowParametersPanel && (
<> <>
<Panel <Panel
id="createTab_textParameters" id="textTab_settings"
order={0} order={0}
defaultSize={25} defaultSize={25}
minSize={25} minSize={25}
style={{ position: 'relative' }} style={{ position: 'relative' }}
> >
<CreateTextParameters /> {/* <TextTabSettings /> */}
<PinParametersPanelButton <PinParametersPanelButton
sx={{ position: 'absolute', top: 0, insetInlineEnd: 0 }} sx={{ position: 'absolute', top: 0, insetInlineEnd: 0 }}
/> />
</Panel> </Panel>
{shouldShowImageParameters && (
<>
<ResizeHandle />
<Panel
id="createTab_imageParameters"
order={1}
defaultSize={25}
minSize={25}
style={{ position: 'relative' }}
>
<CreateImageSettings />
</Panel>
</>
)}
<ResizeHandle /> <ResizeHandle />
</> </>
)} )}
<Panel <Panel
id="createTab_content" id="textTab_main"
order={2} order={2}
minSize={30} minSize={30}
onResize={() => { onResize={() => {
dispatch(requestCanvasRescale()); dispatch(requestCanvasRescale());
}} }}
> >
<CreateTabContent /> {/* <TextTabMain /> */}
</Panel> </Panel>
{shouldPinGallery && shouldShowGallery && (
<>
<ResizeHandle />
<Panel id="createTab_gallery" order={3} defaultSize={10} minSize={10}>
<ImageGalleryContent />
</Panel>
</>
)}
</PanelGroup> </PanelGroup>
); );
}; };
export default memo(CreateTab); export default memo(TextTab);

View File

@ -0,0 +1,78 @@
import { Portal, TabPanel } from '@chakra-ui/react';
import { memo } from 'react';
import { Panel, PanelGroup } from 'react-resizable-panels';
import PinParametersPanelButton from '../../PinParametersPanelButton';
import { createSelector } from '@reduxjs/toolkit';
import { uiSelector } from 'features/ui/store/uiSelectors';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale';
import TextTabMain from './TextTabMain';
import ResizeHandle from '../ResizeHandle';
import TextTabSettings from './TextTabParameters';
const selector = createSelector(uiSelector, (ui) => {
const {
shouldPinGallery,
shouldShowGallery,
shouldPinParametersPanel,
shouldShowParametersPanel,
shouldShowImageParameters,
} = ui;
return {
shouldPinGallery,
shouldShowGallery,
shouldPinParametersPanel,
shouldShowParametersPanel,
shouldShowImageParameters,
};
});
const TextTab = () => {
const dispatch = useAppDispatch();
const {
shouldPinGallery,
shouldShowGallery,
shouldPinParametersPanel,
shouldShowParametersPanel,
shouldShowImageParameters,
} = useAppSelector(selector);
return (
<PanelGroup
autoSaveId="textTab"
direction="horizontal"
style={{ height: '100%', width: '100%' }}
>
{shouldPinParametersPanel && shouldShowParametersPanel && (
<>
<Panel
id="textTab_settings"
order={0}
defaultSize={25}
minSize={25}
style={{ position: 'relative' }}
>
<TextTabSettings />
<PinParametersPanelButton
sx={{ position: 'absolute', top: 0, insetInlineEnd: 0 }}
/>
</Panel>
<ResizeHandle />
</>
)}
<Panel
id="textTab_main"
order={2}
minSize={30}
onResize={() => {
dispatch(requestCanvasRescale());
}}
>
<TextTabMain />
</Panel>
</PanelGroup>
);
};
export default memo(TextTab);

View File

@ -2,7 +2,7 @@ import { Box, Flex } from '@chakra-ui/react';
import CurrentImageDisplay from 'features/gallery/components/CurrentImageDisplay'; import CurrentImageDisplay from 'features/gallery/components/CurrentImageDisplay';
import ProgressImagePreview from 'features/parameters/components/ProgressImagePreview'; import ProgressImagePreview from 'features/parameters/components/ProgressImagePreview';
const CreateTabContent = () => { const TextTabMain = () => {
return ( return (
<Box <Box
sx={{ sx={{
@ -26,4 +26,4 @@ const CreateTabContent = () => {
); );
}; };
export default CreateTabContent; export default TextTabMain;

View File

@ -0,0 +1,108 @@
import { Box, Flex } from '@chakra-ui/react';
import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons';
import { memo } from 'react';
import OverlayScrollable from '../../common/OverlayScrollable';
import ParamPositiveConditioning from 'features/parameters/components/Parameters/ParamPositiveConditioning';
import ParamNegativeConditioning from 'features/parameters/components/Parameters/ParamNegativeConditioning';
import { createSelector } from '@reduxjs/toolkit';
import { uiSelector } from 'features/ui/store/uiSelectors';
import { useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import ParamIterations from 'features/parameters/components/Parameters/ParamIterations';
import ParamSteps from 'features/parameters/components/Parameters/ParamSteps';
import ParamCFGScale from 'features/parameters/components/Parameters/ParamCFGScale';
import ParamWidth from 'features/parameters/components/Parameters/ParamWidth';
import ParamHeight from 'features/parameters/components/Parameters/ParamHeight';
import ParamScheduler from 'features/parameters/components/Parameters/ParamScheduler';
import ModelSelect from 'features/system/components/ModelSelect';
import ParamSeedCollapse from 'features/parameters/components/Parameters/Seed/ParamSeedCollapse';
import ParamVariationCollapse from 'features/parameters/components/Parameters/Variations/ParamVariationCollapse';
import ParamNoiseCollapse from 'features/parameters/components/Parameters/Noise/ParamNoiseCollapse';
import ParamSymmetryCollapse from 'features/parameters/components/Parameters/Symmetry/ParamSymmetryCollapse';
import ParamHiresCollapse from 'features/parameters/components/Parameters/Hires/ParamHiresCollapse';
import ParamSeamlessCollapse from 'features/parameters/components/Parameters/Seamless/ParamSeamlessCollapse';
const selector = createSelector(
uiSelector,
(ui) => {
const { shouldUseSliders } = ui;
return { shouldUseSliders };
},
defaultSelectorOptions
);
const TextTabParameters = () => {
const { shouldUseSliders } = useAppSelector(selector);
return (
<OverlayScrollable>
<Flex
sx={{
gap: 2,
flexDirection: 'column',
h: 'full',
w: 'full',
position: 'absolute',
}}
>
<ParamPositiveConditioning />
<ParamNegativeConditioning />
<ProcessButtons />
<Flex
sx={{
flexDirection: 'column',
gap: 2,
bg: 'base.800',
p: 4,
borderRadius: 'base',
}}
>
{shouldUseSliders ? (
<Flex sx={{ gap: 3, flexDirection: 'column' }}>
<ParamIterations />
<ParamSteps />
<ParamCFGScale />
<ParamWidth />
<ParamHeight />
<Flex gap={3} w="full">
<Box flexGrow={2}>
<ParamScheduler />
</Box>
<Box flexGrow={3}>
<ModelSelect />
</Box>
</Flex>
</Flex>
) : (
<Flex sx={{ gap: 2, flexDirection: 'column' }}>
<Flex gap={3}>
<ParamIterations />
<ParamSteps />
<ParamCFGScale />
</Flex>
<Flex gap={3} w="full">
<Box flexGrow={2}>
<ParamScheduler />
</Box>
<Box flexGrow={3}>
<ModelSelect />
</Box>
</Flex>
<ParamWidth />
<ParamHeight />
</Flex>
)}
</Flex>
<ParamSeedCollapse />
<ParamVariationCollapse />
<ParamNoiseCollapse />
<ParamSymmetryCollapse />
<ParamHiresCollapse />
<ParamSeamlessCollapse />
</Flex>
</OverlayScrollable>
);
};
export default memo(TextTabParameters);

View File

@ -3,12 +3,12 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { uiSelector } from 'features/ui/store/uiSelectors'; import { uiSelector } from 'features/ui/store/uiSelectors';
import { memo } from 'react'; import { memo } from 'react';
import { Panel } from 'react-resizable-panels'; import { Panel } from 'react-resizable-panels';
import CreateTextParameters from './CreateBaseSettings'; import CreateTextParameters from './TextTabParameters';
import PinParametersPanelButton from '../../PinParametersPanelButton'; import PinParametersPanelButton from '../../PinParametersPanelButton';
import ResizeHandle from '../ResizeHandle'; import ResizeHandle from '../ResizeHandle';
import ImageToImageSettings from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageSettings'; import ImageToImageSettings from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageSettings';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import CreateImageSettings from './CreateImageSettings'; import CreateImageSettings from '../image/ImageTabSettings';
const selector = createSelector( const selector = createSelector(
uiSelector, uiSelector,

View File

@ -1,7 +1,7 @@
export const tabMap = [ export const tabMap = [
// 'txt2img', 'text',
// 'img2img', 'image',
'generate', // 'generate',
'unifiedCanvas', 'unifiedCanvas',
'nodes', 'nodes',
// 'postprocessing', // 'postprocessing',

View File

@ -18,9 +18,9 @@ export const initialUIState: UIState = {
shouldPinGallery: true, shouldPinGallery: true,
shouldShowGallery: true, shouldShowGallery: true,
shouldHidePreview: false, shouldHidePreview: false,
openLinearAccordionItems: [], textTabAccordionState: [],
openGenerateAccordionItems: [], imageTabAccordionState: [],
openUnifiedCanvasAccordionItems: [], canvasTabAccordionState: [],
floatingProgressImageRect: { x: 0, y: 0, width: 0, height: 0 }, floatingProgressImageRect: { x: 0, y: 0, width: 0, height: 0 },
shouldShowProgressImages: false, shouldShowProgressImages: false,
shouldAutoShowProgressImages: false, shouldAutoShowProgressImages: false,
@ -105,12 +105,16 @@ export const uiSlice = createSlice({
} }
}, },
openAccordionItemsChanged: (state, action: PayloadAction<number[]>) => { openAccordionItemsChanged: (state, action: PayloadAction<number[]>) => {
if (tabMap[state.activeTab] === 'generate') { if (tabMap[state.activeTab] === 'text') {
state.openGenerateAccordionItems = action.payload; state.textTabAccordionState = action.payload;
}
if (tabMap[state.activeTab] === 'image') {
state.imageTabAccordionState = action.payload;
} }
if (tabMap[state.activeTab] === 'unifiedCanvas') { if (tabMap[state.activeTab] === 'unifiedCanvas') {
state.openUnifiedCanvasAccordionItems = action.payload; state.canvasTabAccordionState = action.payload;
} }
}, },
floatingProgressImageMoved: (state, action: PayloadAction<Coordinates>) => { floatingProgressImageMoved: (state, action: PayloadAction<Coordinates>) => {

View File

@ -26,9 +26,9 @@ export interface UIState {
shouldHidePreview: boolean; shouldHidePreview: boolean;
shouldPinGallery: boolean; shouldPinGallery: boolean;
shouldShowGallery: boolean; shouldShowGallery: boolean;
openLinearAccordionItems: number[]; textTabAccordionState: number[];
openGenerateAccordionItems: number[]; imageTabAccordionState: number[];
openUnifiedCanvasAccordionItems: number[]; canvasTabAccordionState: number[];
floatingProgressImageRect: Rect; floatingProgressImageRect: Rect;
shouldShowProgressImages: boolean; shouldShowProgressImages: boolean;
shouldAutoShowProgressImages: boolean; shouldAutoShowProgressImages: boolean;