feat(ui): more work on controlnet mini

This commit is contained in:
psychedelicious
2023-06-03 13:06:37 +10:00
parent b6b3b9f99c
commit a0dde66b5d
9 changed files with 166 additions and 92 deletions

View File

@@ -58,11 +58,7 @@ const ControlNet = (props: ControlNetProps) => {
return (
<Flex sx={{ flexDir: 'column', gap: 3 }}>
<ControlNetImagePreview
controlNetId={controlNetId}
controlImage={controlImage}
processedControlImage={processedControlImage}
/>
<ControlNetImagePreview controlNet={props.controlNet} />
<ParamControlNetModel controlNetId={controlNetId} model={model} />
<Tabs
isFitted

View File

@@ -1,6 +1,7 @@
import { memo, useCallback, useState } from 'react';
import { memo, useCallback, useRef, useState } from 'react';
import { ImageDTO } from 'services/api';
import {
ControlNet,
controlNetImageChanged,
controlNetSelector,
} from '../store/controlNetSlice';
@@ -11,6 +12,7 @@ import { createSelector } from '@reduxjs/toolkit';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import { AnimatePresence, motion } from 'framer-motion';
import { IAIImageFallback } from 'common/components/IAIImageFallback';
import { useHoverDirty } from 'react-use';
const selector = createSelector(
controlNetSelector,
@@ -22,18 +24,21 @@ const selector = createSelector(
);
type Props = {
controlNetId: string;
controlImage: ImageDTO | null;
processedControlImage: ImageDTO | null;
controlNet: ControlNet;
};
const ControlNetImagePreview = (props: Props) => {
const { controlNetId, controlImage, processedControlImage } = props;
const {
controlNetId,
controlImage,
processedControlImage,
isControlImageProcessed,
} = props.controlNet;
const dispatch = useAppDispatch();
const { isProcessingControlImage } = useAppSelector(selector);
const containerRef = useRef<HTMLDivElement>(null);
const [shouldShowProcessedImage, setShouldShowProcessedImage] =
useState(true);
const isMouseOverImage = useHoverDirty(containerRef);
const handleControlImageChanged = useCallback(
(controlImage: ImageDTO) => {
@@ -46,12 +51,15 @@ const ControlNetImagePreview = (props: Props) => {
Number(controlImage?.width) > Number(processedControlImage?.width) ||
Number(controlImage?.height) > Number(processedControlImage?.height);
const shouldShowProcessedImage =
controlImage &&
processedControlImage &&
!isMouseOverImage &&
!isProcessingControlImage &&
!isControlImageProcessed;
return (
<Box
sx={{ position: 'relative', h: 'inherit' }}
onMouseOver={() => setShouldShowProcessedImage(false)}
onMouseOut={() => setShouldShowProcessedImage(true)}
>
<Box ref={containerRef} sx={{ position: 'relative', w: 'full', h: 'full' }}>
<IAIDndImage
image={controlImage}
onDrop={handleControlImageChanged}

View File

@@ -1,29 +1,26 @@
import { memo, useCallback } from 'react';
import {
ControlNet,
controlNetProcessedImageChanged,
controlNetAdded,
controlNetRemoved,
controlNetToggled,
isControlNetImageProcessedToggled,
} from '../store/controlNetSlice';
import { useAppDispatch } from 'app/store/storeHooks';
import ParamControlNetModel from './parameters/ParamControlNetModel';
import ParamControlNetWeight from './parameters/ParamControlNetWeight';
import {
Box,
Checkbox,
Flex,
Tab,
TabList,
TabPanel,
TabPanels,
Tabs,
Text,
FormControl,
FormLabel,
HStack,
} from '@chakra-ui/react';
import IAIButton from 'common/components/IAIButton';
import { FaUndo } from 'react-icons/fa';
import ParamControlNetProcessorSelect from './parameters/ParamControlNetProcessorSelect';
import ControlNetProcessorComponent from './ControlNetProcessorComponent';
import ControlNetPreprocessButton from './ControlNetPreprocessButton';
import { FaCopy, FaTrash } from 'react-icons/fa';
import ParamControlNetBeginEnd from './parameters/ParamControlNetBeginEnd';
import ControlNetImagePreview from './ControlNetImagePreview';
import IAIIconButton from 'common/components/IAIIconButton';
import { v4 as uuidv4 } from 'uuid';
type ControlNetProps = {
controlNet: ControlNet;
@@ -43,56 +40,111 @@ const ControlNet = (props: ControlNetProps) => {
processorNode,
} = props.controlNet;
const dispatch = useAppDispatch();
const handleReset = useCallback(() => {
dispatch(
controlNetProcessedImageChanged({
controlNetId,
processedControlImage: null,
})
);
const handleDelete = useCallback(() => {
dispatch(controlNetRemoved(controlNetId));
}, [controlNetId, dispatch]);
const handleControlNetRemoved = useCallback(() => {
dispatch(controlNetRemoved(controlNetId));
const handleDuplicate = useCallback(() => {
dispatch(
controlNetAdded({ controlNetId: uuidv4(), controlNet: props.controlNet })
);
}, [dispatch, props.controlNet]);
const handleToggleIsEnabled = useCallback(() => {
dispatch(controlNetToggled(controlNetId));
}, [controlNetId, dispatch]);
const handleToggleIsPreprocessed = useCallback(() => {
dispatch(isControlNetImageProcessedToggled(controlNetId));
}, [controlNetId, dispatch]);
return (
<Flex
sx={{
gap: 4,
p: 2,
paddingInlineEnd: 4,
bg: 'base.850',
borderRadius: 'base',
flexDir: 'column',
gap: 2,
}}
>
<HStack>
<ParamControlNetModel controlNetId={controlNetId} model={model} />
<IAIIconButton
size="sm"
tooltip="Duplicate ControlNet"
aria-label="Duplicate ControlNet"
onClick={handleDuplicate}
icon={<FaCopy />}
/>
<IAIIconButton
size="sm"
tooltip="Delete ControlNet"
aria-label="Delete ControlNet"
colorScheme="error"
onClick={handleDelete}
icon={<FaTrash />}
/>
</HStack>
<Flex
sx={{
alignItems: 'center',
justifyContent: 'center',
h: 36,
w: 36,
gap: 4,
paddingInlineEnd: 2,
}}
>
<ControlNetImagePreview
controlNetId={controlNetId}
controlImage={controlImage}
processedControlImage={processedControlImage}
/>
</Flex>
<Flex sx={{ flexDir: 'column', gap: 2, w: 'full', h: 'full' }}>
<ParamControlNetModel controlNetId={controlNetId} model={model} />
<ParamControlNetWeight
controlNetId={controlNetId}
weight={weight}
mini
/>
<ParamControlNetBeginEnd
controlNetId={controlNetId}
beginStepPct={beginStepPct}
endStepPct={endStepPct}
mini
/>
<Flex
sx={{
alignItems: 'center',
justifyContent: 'center',
h: 32,
w: 32,
aspectRatio: '1/1',
}}
>
<ControlNetImagePreview controlNet={props.controlNet} />
</Flex>
<Flex
sx={{
flexDir: 'column',
gap: 2,
w: 'full',
justifyContent: 'space-between',
}}
>
<ParamControlNetWeight
controlNetId={controlNetId}
weight={weight}
mini
/>
<ParamControlNetBeginEnd
controlNetId={controlNetId}
beginStepPct={beginStepPct}
endStepPct={endStepPct}
mini
/>
<Flex
sx={{
justifyContent: 'space-between',
}}
>
<FormControl>
<HStack>
<Checkbox
isChecked={isEnabled}
onChange={handleToggleIsEnabled}
/>
<FormLabel>Enabled</FormLabel>
</HStack>
</FormControl>
<FormControl>
<HStack>
<Checkbox
isChecked={isControlImageProcessed}
onChange={handleToggleIsPreprocessed}
/>
<FormLabel>Preprocessed</FormLabel>
</HStack>
</FormControl>
</Flex>
</Flex>
</Flex>
</Flex>
);

View File

@@ -50,7 +50,7 @@ const ParamControlNetBeginEnd = (props: Props) => {
return (
<FormControl>
<FormLabel>Begin & End Step %</FormLabel>
<FormLabel>Begin / End Step Percentage</FormLabel>
<HStack w="100%" gap={2} alignItems="center">
<RangeSlider
aria-label={['Begin Step %', 'End Step %']}
@@ -72,7 +72,6 @@ const ParamControlNetBeginEnd = (props: Props) => {
</Tooltip>
{!mini && (
<>
{' '}
<RangeSliderMark
value={0}
sx={{

View File

@@ -72,11 +72,11 @@ export const controlNetSlice = createSlice({
},
controlNetAdded: (
state,
action: PayloadAction<{ controlNetId: string }>
action: PayloadAction<{ controlNetId: string; controlNet?: ControlNet }>
) => {
const { controlNetId } = action.payload;
const { controlNetId, controlNet } = action.payload;
state.controlNets[controlNetId] = {
...initialControlNet,
...(controlNet ?? initialControlNet),
controlNetId,
};
},
@@ -116,11 +116,9 @@ export const controlNetSlice = createSlice({
},
isControlNetImageProcessedToggled: (
state,
action: PayloadAction<{
controlNetId: string;
}>
action: PayloadAction<string>
) => {
const { controlNetId } = action.payload;
const controlNetId = action.payload;
state.controlNets[controlNetId].isControlImageProcessed =
!state.controlNets[controlNetId].isControlImageProcessed;
},