build out the rest of the accordions

This commit is contained in:
Mary Hipp 2024-07-17 12:05:11 -04:00 committed by psychedelicious
parent a0a54348e8
commit fd91b83d86
8 changed files with 268 additions and 18 deletions

View File

@ -0,0 +1,55 @@
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { setSteps } from 'features/parameters/store/generationSlice';
import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
const ParamCreativity = () => {
const steps = useAppSelector((s) => s.generation.steps);
const initial = useAppSelector((s) => s.config.sd.steps.initial);
const sliderMin = useAppSelector((s) => s.config.sd.steps.sliderMin);
const sliderMax = useAppSelector((s) => s.config.sd.steps.sliderMax);
const numberInputMin = useAppSelector((s) => s.config.sd.steps.numberInputMin);
const numberInputMax = useAppSelector((s) => s.config.sd.steps.numberInputMax);
const coarseStep = useAppSelector((s) => s.config.sd.steps.coarseStep);
const fineStep = useAppSelector((s) => s.config.sd.steps.fineStep);
const dispatch = useAppDispatch();
const { t } = useTranslation();
const marks = useMemo(() => [sliderMin, Math.floor(sliderMax / 2), sliderMax], [sliderMax, sliderMin]);
const onChange = useCallback(
(v: number) => {
dispatch(setSteps(v));
},
[dispatch]
);
return (
<FormControl>
<InformationalPopover feature="paramSteps">
<FormLabel>Creativity</FormLabel>
</InformationalPopover>
<CompositeSlider
value={steps}
defaultValue={initial}
min={sliderMin}
max={sliderMax}
step={coarseStep}
fineStep={fineStep}
onChange={onChange}
marks={marks}
/>
<CompositeNumberInput
value={steps}
defaultValue={initial}
min={numberInputMin}
max={numberInputMax}
step={coarseStep}
fineStep={fineStep}
onChange={onChange}
/>
</FormControl>
);
};
export default memo(ParamCreativity);

View File

@ -0,0 +1,55 @@
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { setSteps } from 'features/parameters/store/generationSlice';
import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
const ParamSharpness = () => {
const steps = useAppSelector((s) => s.generation.steps);
const initial = useAppSelector((s) => s.config.sd.steps.initial);
const sliderMin = useAppSelector((s) => s.config.sd.steps.sliderMin);
const sliderMax = useAppSelector((s) => s.config.sd.steps.sliderMax);
const numberInputMin = useAppSelector((s) => s.config.sd.steps.numberInputMin);
const numberInputMax = useAppSelector((s) => s.config.sd.steps.numberInputMax);
const coarseStep = useAppSelector((s) => s.config.sd.steps.coarseStep);
const fineStep = useAppSelector((s) => s.config.sd.steps.fineStep);
const dispatch = useAppDispatch();
const { t } = useTranslation();
const marks = useMemo(() => [sliderMin, Math.floor(sliderMax / 2), sliderMax], [sliderMax, sliderMin]);
const onChange = useCallback(
(v: number) => {
dispatch(setSteps(v));
},
[dispatch]
);
return (
<FormControl>
<InformationalPopover feature="paramSteps">
<FormLabel>Sharpness</FormLabel>
</InformationalPopover>
<CompositeSlider
value={steps}
defaultValue={initial}
min={sliderMin}
max={sliderMax}
step={coarseStep}
fineStep={fineStep}
onChange={onChange}
marks={marks}
/>
<CompositeNumberInput
value={steps}
defaultValue={initial}
min={numberInputMin}
max={numberInputMax}
step={coarseStep}
fineStep={fineStep}
onChange={onChange}
/>
</FormControl>
);
};
export default memo(ParamSharpness);

View File

@ -0,0 +1,55 @@
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { setSteps } from 'features/parameters/store/generationSlice';
import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
const ParamStructure = () => {
const steps = useAppSelector((s) => s.generation.steps);
const initial = useAppSelector((s) => s.config.sd.steps.initial);
const sliderMin = useAppSelector((s) => s.config.sd.steps.sliderMin);
const sliderMax = useAppSelector((s) => s.config.sd.steps.sliderMax);
const numberInputMin = useAppSelector((s) => s.config.sd.steps.numberInputMin);
const numberInputMax = useAppSelector((s) => s.config.sd.steps.numberInputMax);
const coarseStep = useAppSelector((s) => s.config.sd.steps.coarseStep);
const fineStep = useAppSelector((s) => s.config.sd.steps.fineStep);
const dispatch = useAppDispatch();
const { t } = useTranslation();
const marks = useMemo(() => [sliderMin, Math.floor(sliderMax / 2), sliderMax], [sliderMax, sliderMin]);
const onChange = useCallback(
(v: number) => {
dispatch(setSteps(v));
},
[dispatch]
);
return (
<FormControl>
<InformationalPopover feature="paramSteps">
<FormLabel>Structure</FormLabel>
</InformationalPopover>
<CompositeSlider
value={steps}
defaultValue={initial}
min={sliderMin}
max={sliderMax}
step={coarseStep}
fineStep={fineStep}
onChange={onChange}
marks={marks}
/>
<CompositeNumberInput
value={steps}
defaultValue={initial}
min={numberInputMin}
max={numberInputMax}
step={coarseStep}
fineStep={fineStep}
onChange={onChange}
/>
</FormControl>
);
};
export default memo(ParamStructure);

View File

@ -14,7 +14,7 @@ interface UpscaleState {
const initialUpscaleState: UpscaleState = { const initialUpscaleState: UpscaleState = {
_version: 1, _version: 1,
upscaleModel: null, upscaleModel: null,
upscaleInitialImage: null upscaleInitialImage: null,
}; };
export const upscaleSlice = createSlice({ export const upscaleSlice = createSlice({

View File

@ -14,6 +14,10 @@ import { useStandaloneAccordionToggle } from 'features/settingsAccordions/hooks/
import { memo, useMemo } from 'react'; import { memo, useMemo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useGetModelConfigQuery } from 'services/api/endpoints/models'; import { useGetModelConfigQuery } from 'services/api/endpoints/models';
import { activeTabNameSelector } from '../../../ui/store/uiSelectors';
import { ParamSeedNumberInput } from '../../../parameters/components/Seed/ParamSeedNumberInput';
import { ParamSeedRandomize } from '../../../parameters/components/Seed/ParamSeedRandomize';
import { ParamSeedShuffle } from '../../../parameters/components/Seed/ParamSeedShuffle';
const formLabelProps: FormLabelProps = { const formLabelProps: FormLabelProps = {
minW: '9.2rem', minW: '9.2rem',
@ -26,6 +30,8 @@ const formLabelProps2: FormLabelProps = {
export const AdvancedSettingsAccordion = memo(() => { export const AdvancedSettingsAccordion = memo(() => {
const vaeKey = useAppSelector((state) => state.generation.vae?.key); const vaeKey = useAppSelector((state) => state.generation.vae?.key);
const { currentData: vaeConfig } = useGetModelConfigQuery(vaeKey ?? skipToken); const { currentData: vaeConfig } = useGetModelConfigQuery(vaeKey ?? skipToken);
const activeTabName = useAppSelector(activeTabNameSelector);
const selectBadges = useMemo( const selectBadges = useMemo(
() => () =>
createMemoizedSelector(selectGenerationSlice, (generation) => { createMemoizedSelector(selectGenerationSlice, (generation) => {
@ -48,9 +54,12 @@ export const AdvancedSettingsAccordion = memo(() => {
if (generation.seamlessXAxis || generation.seamlessYAxis) { if (generation.seamlessXAxis || generation.seamlessYAxis) {
badges.push('seamless'); badges.push('seamless');
} }
if (activeTabName === 'upscaling' && !generation.shouldRandomizeSeed) {
badges.push('Manual Seed');
}
return badges; return badges;
}), }),
[vaeConfig] [vaeConfig, activeTabName]
); );
const badges = useAppSelector(selectBadges); const badges = useAppSelector(selectBadges);
const { t } = useTranslation(); const { t } = useTranslation();
@ -66,16 +75,27 @@ export const AdvancedSettingsAccordion = memo(() => {
<ParamVAEModelSelect /> <ParamVAEModelSelect />
<ParamVAEPrecision /> <ParamVAEPrecision />
</Flex> </Flex>
<FormControlGroup formLabelProps={formLabelProps}> {activeTabName === 'upscaling' && (
<ParamClipSkip /> <Flex gap={4} alignItems="center">
<ParamCFGRescaleMultiplier /> <ParamSeedNumberInput />
</FormControlGroup> <ParamSeedShuffle />
<Flex gap={4} w="full"> <ParamSeedRandomize />
<FormControlGroup formLabelProps={formLabelProps2}> </Flex>
<ParamSeamlessXAxis /> )}
<ParamSeamlessYAxis /> {activeTabName !== 'upscaling' && (
</FormControlGroup> <>
</Flex> <FormControlGroup formLabelProps={formLabelProps}>
<ParamClipSkip />
<ParamCFGRescaleMultiplier />
</FormControlGroup>
<Flex gap={4} w="full">
<FormControlGroup formLabelProps={formLabelProps2}>
<ParamSeamlessXAxis />
<ParamSeamlessYAxis />
</FormControlGroup>
</Flex>
</>
)}
</Flex> </Flex>
</StandaloneAccordion> </StandaloneAccordion>
); );

View File

@ -1,24 +1,58 @@
import { Flex, StandaloneAccordion } from '@invoke-ai/ui-library'; import { Expander, Flex, StandaloneAccordion } from '@invoke-ai/ui-library';
import { useStandaloneAccordionToggle } from 'features/settingsAccordions/hooks/useStandaloneAccordionToggle'; import { useStandaloneAccordionToggle } from 'features/settingsAccordions/hooks/useStandaloneAccordionToggle';
import { memo } from 'react'; import { memo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import ParamSpandrelModel from '../../../parameters/components/Upscale/ParamSpandrelModel'; import ParamSpandrelModel from '../../../parameters/components/Upscale/ParamSpandrelModel';
import { UpscaleInitialImage } from './UpscaleInitialImage'; import { UpscaleInitialImage } from './UpscaleInitialImage';
import { UpscaleSizeDetails } from './UpscaleSizeDetails';
import { useExpanderToggle } from '../../hooks/useExpanderToggle';
import ParamSharpness from '../../../parameters/components/Upscale/ParamSharpness';
import ParamCreativity from '../../../parameters/components/Upscale/ParamCreativity';
import ParamStructure from '../../../parameters/components/Upscale/ParamStructure';
import { selectUpscalelice } from '../../../parameters/store/upscaleSlice';
import { createMemoizedSelector } from '../../../../app/store/createMemoizedSelector';
import { useAppSelector } from '../../../../app/store/storeHooks';
const selector = createMemoizedSelector([selectUpscalelice], (upscale) => {
const badges: string[] = [];
if (upscale.upscaleModel) {
badges.push(upscale.upscaleModel.name);
}
return { badges };
});
export const UpscaleSettingsAccordion = memo(() => { export const UpscaleSettingsAccordion = memo(() => {
const { t } = useTranslation(); const { t } = useTranslation();
const { badges } = useAppSelector(selector);
const { isOpen: isOpenAccordion, onToggle: onToggleAccordion } = useStandaloneAccordionToggle({ const { isOpen: isOpenAccordion, onToggle: onToggleAccordion } = useStandaloneAccordionToggle({
id: 'upscale-settings', id: 'upscale-settings',
defaultIsOpen: true, defaultIsOpen: true,
}); });
const { isOpen: isOpenExpander, onToggle: onToggleExpander } = useExpanderToggle({
id: 'upscale-settings-advanced',
defaultIsOpen: false,
});
return ( return (
<StandaloneAccordion label="Upscale" isOpen={isOpenAccordion} onToggle={onToggleAccordion}> <StandaloneAccordion label="Upscale" badges={badges} isOpen={isOpenAccordion} onToggle={onToggleAccordion}>
<Flex p={4} w="full" h="full" flexDir="column" data-testid="image-settings-accordion"> <Flex pt={4} px={4} w="full" h="full" flexDir="column" data-testid="image-settings-accordion">
<Flex gap={4}> <Flex gap={4}>
<UpscaleInitialImage /> <UpscaleInitialImage />
<ParamSpandrelModel /> <Flex direction="column" w="full" alignItems="center" gap={4}>
<ParamSpandrelModel />
<UpscaleSizeDetails />
</Flex>
</Flex> </Flex>
<Expander label={t('accordions.advanced.options')} isOpen={isOpenExpander} onToggle={onToggleExpander}>
<Flex gap={4} pb={4} flexDir="column">
<ParamSharpness />
<ParamCreativity />
<ParamStructure />
</Flex>
</Expander>
</Flex> </Flex>
</StandaloneAccordion> </StandaloneAccordion>
); );

View File

@ -0,0 +1,31 @@
import { Flex, Text } from '@invoke-ai/ui-library';
import { useAppSelector } from '../../../../app/store/storeHooks';
import { useMemo } from 'react';
export const UpscaleSizeDetails = () => {
const { upscaleInitialImage, upscaleModel } = useAppSelector((s) => s.upscale);
const scaleFactor = useMemo(() => {
if (upscaleModel) {
const upscaleFactor = upscaleModel.name.match(/x(\d+)/);
if (upscaleFactor && upscaleFactor[1]) {
return parseInt(upscaleFactor[1], 10);
}
}
}, [upscaleModel]);
if (!upscaleInitialImage || !upscaleModel || !scaleFactor) {
return <></>;
}
return (
<Flex direction="column">
<Text variant="subtext" fontWeight="bold">
Current image size: {upscaleInitialImage.width} x {upscaleInitialImage.height}
</Text>
<Text variant="subtext" fontWeight="bold">
Output image size: {upscaleInitialImage.width * scaleFactor} x {upscaleInitialImage.height * scaleFactor}
</Text>
</Flex>
);
};

View File

@ -1,4 +1,4 @@
import { Box, Flex, Switch } from '@invoke-ai/ui-library'; import { Box, Divider, Flex } from '@invoke-ai/ui-library';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { overlayScrollbarsParams } from 'common/components/OverlayScrollbars/constants'; import { overlayScrollbarsParams } from 'common/components/OverlayScrollbars/constants';
import { Prompts } from 'features/parameters/components/Prompts/Prompts'; import { Prompts } from 'features/parameters/components/Prompts/Prompts';
@ -29,8 +29,8 @@ const ParametersPanelUpscale = () => {
<Box position="absolute" top={0} left={0} right={0} bottom={0}> <Box position="absolute" top={0} left={0} right={0} bottom={0}>
<OverlayScrollbarsComponent defer style={overlayScrollbarsStyles} options={overlayScrollbarsParams.options}> <OverlayScrollbarsComponent defer style={overlayScrollbarsStyles} options={overlayScrollbarsParams.options}>
<Flex gap={2} flexDirection="column" h="full" w="full"> <Flex gap={2} flexDirection="column" h="full" w="full">
<UpscaleSettingsAccordion />
{isSDXL ? <SDXLPrompts /> : <Prompts />} {isSDXL ? <SDXLPrompts /> : <Prompts />}
<UpscaleSettingsAccordion />
<GenerationSettingsAccordion /> <GenerationSettingsAccordion />
<AdvancedSettingsAccordion /> <AdvancedSettingsAccordion />
</Flex> </Flex>