Adds "loopback" feature

This commit is contained in:
psychedelicious 2022-10-30 19:32:32 +11:00
parent 2d32cf4eeb
commit 6547c320a9
11 changed files with 589 additions and 535 deletions

517
frontend/dist/assets/index.1ad4a17a.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -6,8 +6,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>InvokeAI - A Stable Diffusion Toolkit</title>
<link rel="shortcut icon" type="icon" href="./assets/favicon.0d253ced.ico" />
<script type="module" crossorigin src="./assets/index.616d87b3.js"></script>
<link rel="stylesheet" href="./assets/index.64a76932.css">
<script type="module" crossorigin src="./assets/index.1ad4a17a.js"></script>
<link rel="stylesheet" href="./assets/index.c4f22615.css">
</head>
<body>

View File

@ -37,6 +37,7 @@ import {
clearImageToInpaint,
setImageToInpaint,
} from '../../features/tabs/Inpainting/inpaintingSlice';
import { tabMap } from '../../features/tabs/InvokeTabs';
/**
* Returns an object containing listener callbacks for socketio events.
@ -96,16 +97,34 @@ const makeSocketIOListeners = (
*/
onGenerationResult: (data: InvokeAI.ImageResultResponse) => {
try {
const { shouldLoopback, activeTab } = getState().options;
const newImage = {
uuid: uuidv4(),
...data,
category: 'result',
};
dispatch(
addImage({
category: 'result',
image: {
uuid: uuidv4(),
...data,
category: 'result',
},
image: newImage,
})
);
if (shouldLoopback) {
const activeTabName = tabMap[activeTab];
switch (activeTabName) {
case 'img2img': {
dispatch(setInitialImage(newImage));
break;
}
case 'inpainting': {
dispatch(setImageToInpaint(newImage));
break;
}
}
}
dispatch(
addLogEntry({
timestamp: dateFormat(new Date(), 'isoDateTime'),

View File

@ -0,0 +1,24 @@
import { FaRecycle } from 'react-icons/fa';
import { RootState, useAppDispatch, useAppSelector } from '../../../app/store';
import IAIIconButton from '../../../common/components/IAIIconButton';
import { setShouldLoopback } from '../optionsSlice';
const LoopbackButton = () => {
const dispatch = useAppDispatch();
const { shouldLoopback } = useAppSelector(
(state: RootState) => state.options
);
return (
<IAIIconButton
aria-label="Loopback"
tooltip="Loopback"
data-selected={shouldLoopback}
icon={<FaRecycle />}
onClick={() => {
dispatch(setShouldLoopback(!shouldLoopback));
}}
/>
);
};
export default LoopbackButton;

View File

@ -2,7 +2,7 @@
.process-buttons {
display: grid;
grid-template-columns: auto max-content;
grid-template-columns: auto max-content max-content;
column-gap: 0.5rem;
}

View File

@ -1,5 +1,6 @@
import InvokeButton from './InvokeButton';
import CancelButton from './CancelButton';
import LoopbackButton from './Loopback';
/**
* Buttons to start and cancel image generation.
@ -8,6 +9,7 @@ const ProcessButtons = () => {
return (
<div className="process-buttons">
<InvokeButton />
<LoopbackButton />
<CancelButton />
</div>
);

View File

@ -46,6 +46,7 @@ export interface OptionsState {
shouldPinOptionsPanel: boolean;
optionsPanelScrollPosition: number;
shouldHoldOptionsPanelOpen: boolean;
shouldLoopback: boolean;
}
const initialOptionsState: OptionsState = {
@ -83,6 +84,7 @@ const initialOptionsState: OptionsState = {
shouldPinOptionsPanel: true,
optionsPanelScrollPosition: 0,
shouldHoldOptionsPanelOpen: false,
shouldLoopback: true,
};
const initialState: OptionsState = initialOptionsState;
@ -344,6 +346,9 @@ export const optionsSlice = createSlice({
setShouldHoldOptionsPanelOpen: (state, action: PayloadAction<boolean>) => {
state.shouldHoldOptionsPanelOpen = action.payload;
},
setShouldLoopback: (state, action: PayloadAction<boolean>) => {
state.shouldLoopback = action.payload;
},
},
});
@ -390,6 +395,7 @@ export const {
setShouldPinOptionsPanel,
setOptionsPanelScrollPosition,
setShouldHoldOptionsPanelOpen,
setShouldLoopback,
} = optionsSlice.actions;
export default optionsSlice.reducer;

View File

@ -1,3 +1,4 @@
import { Tooltip } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import {
FocusEvent,
@ -7,7 +8,7 @@ import {
useEffect,
useRef,
} from 'react';
import { BsPinAngleFill } from 'react-icons/bs';
import { BsPinAngle, BsPinAngleFill } from 'react-icons/bs';
import { CSSTransition } from 'react-transition-group';
import { RootState, useAppDispatch, useAppSelector } from '../../app/store';
import IAIIconButton from '../../common/components/IAIIconButton';
@ -119,6 +120,16 @@ const InvokeOptionsPanel = (props: Props) => {
!shouldPinOptionsPanel ? cancelCloseOptionsPanelTimer : undefined
}
>
<Tooltip label="Pin Options Panel">
<div
className="options-panel-pin-button"
data-selected={shouldPinOptionsPanel}
onClick={handleClickPinOptionsPanel}
>
{shouldPinOptionsPanel ? <BsPinAngleFill /> : <BsPinAngle />}
</div>
</Tooltip>
<div
className="options-panel"
ref={optionsPanelContainerRef}
@ -130,14 +141,6 @@ const InvokeOptionsPanel = (props: Props) => {
}
}}
>
<IAIIconButton
size={'sm'}
aria-label={'Pin Options Panel'}
tooltip={'Pin Options Panel (Shift+P)'}
onClick={handleClickPinOptionsPanel}
icon={<BsPinAngleFill />}
data-selected={shouldPinOptionsPanel}
/>
{children}
</div>
</div>