mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Adds "loopback" feature
This commit is contained in:
parent
2d32cf4eeb
commit
6547c320a9
517
frontend/dist/assets/index.1ad4a17a.js
vendored
Normal file
517
frontend/dist/assets/index.1ad4a17a.js
vendored
Normal file
File diff suppressed because one or more lines are too long
517
frontend/dist/assets/index.616d87b3.js
vendored
517
frontend/dist/assets/index.616d87b3.js
vendored
File diff suppressed because one or more lines are too long
1
frontend/dist/assets/index.64a76932.css
vendored
1
frontend/dist/assets/index.64a76932.css
vendored
File diff suppressed because one or more lines are too long
1
frontend/dist/assets/index.c4f22615.css
vendored
Normal file
1
frontend/dist/assets/index.c4f22615.css
vendored
Normal file
File diff suppressed because one or more lines are too long
4
frontend/dist/index.html
vendored
4
frontend/dist/index.html
vendored
@ -6,8 +6,8 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>InvokeAI - A Stable Diffusion Toolkit</title>
|
<title>InvokeAI - A Stable Diffusion Toolkit</title>
|
||||||
<link rel="shortcut icon" type="icon" href="./assets/favicon.0d253ced.ico" />
|
<link rel="shortcut icon" type="icon" href="./assets/favicon.0d253ced.ico" />
|
||||||
<script type="module" crossorigin src="./assets/index.616d87b3.js"></script>
|
<script type="module" crossorigin src="./assets/index.1ad4a17a.js"></script>
|
||||||
<link rel="stylesheet" href="./assets/index.64a76932.css">
|
<link rel="stylesheet" href="./assets/index.c4f22615.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
@ -37,6 +37,7 @@ import {
|
|||||||
clearImageToInpaint,
|
clearImageToInpaint,
|
||||||
setImageToInpaint,
|
setImageToInpaint,
|
||||||
} from '../../features/tabs/Inpainting/inpaintingSlice';
|
} from '../../features/tabs/Inpainting/inpaintingSlice';
|
||||||
|
import { tabMap } from '../../features/tabs/InvokeTabs';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an object containing listener callbacks for socketio events.
|
* Returns an object containing listener callbacks for socketio events.
|
||||||
@ -96,16 +97,34 @@ const makeSocketIOListeners = (
|
|||||||
*/
|
*/
|
||||||
onGenerationResult: (data: InvokeAI.ImageResultResponse) => {
|
onGenerationResult: (data: InvokeAI.ImageResultResponse) => {
|
||||||
try {
|
try {
|
||||||
|
const { shouldLoopback, activeTab } = getState().options;
|
||||||
|
const newImage = {
|
||||||
|
uuid: uuidv4(),
|
||||||
|
...data,
|
||||||
|
category: 'result',
|
||||||
|
};
|
||||||
|
|
||||||
dispatch(
|
dispatch(
|
||||||
addImage({
|
addImage({
|
||||||
category: 'result',
|
category: 'result',
|
||||||
image: {
|
image: newImage,
|
||||||
uuid: uuidv4(),
|
|
||||||
...data,
|
|
||||||
category: 'result',
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (shouldLoopback) {
|
||||||
|
const activeTabName = tabMap[activeTab];
|
||||||
|
switch (activeTabName) {
|
||||||
|
case 'img2img': {
|
||||||
|
dispatch(setInitialImage(newImage));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'inpainting': {
|
||||||
|
dispatch(setImageToInpaint(newImage));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dispatch(
|
dispatch(
|
||||||
addLogEntry({
|
addLogEntry({
|
||||||
timestamp: dateFormat(new Date(), 'isoDateTime'),
|
timestamp: dateFormat(new Date(), 'isoDateTime'),
|
||||||
|
24
frontend/src/features/options/ProcessButtons/Loopback.tsx
Normal file
24
frontend/src/features/options/ProcessButtons/Loopback.tsx
Normal 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;
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
.process-buttons {
|
.process-buttons {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: auto max-content;
|
grid-template-columns: auto max-content max-content;
|
||||||
column-gap: 0.5rem;
|
column-gap: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import InvokeButton from './InvokeButton';
|
import InvokeButton from './InvokeButton';
|
||||||
import CancelButton from './CancelButton';
|
import CancelButton from './CancelButton';
|
||||||
|
import LoopbackButton from './Loopback';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Buttons to start and cancel image generation.
|
* Buttons to start and cancel image generation.
|
||||||
@ -8,6 +9,7 @@ const ProcessButtons = () => {
|
|||||||
return (
|
return (
|
||||||
<div className="process-buttons">
|
<div className="process-buttons">
|
||||||
<InvokeButton />
|
<InvokeButton />
|
||||||
|
<LoopbackButton />
|
||||||
<CancelButton />
|
<CancelButton />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -46,6 +46,7 @@ export interface OptionsState {
|
|||||||
shouldPinOptionsPanel: boolean;
|
shouldPinOptionsPanel: boolean;
|
||||||
optionsPanelScrollPosition: number;
|
optionsPanelScrollPosition: number;
|
||||||
shouldHoldOptionsPanelOpen: boolean;
|
shouldHoldOptionsPanelOpen: boolean;
|
||||||
|
shouldLoopback: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialOptionsState: OptionsState = {
|
const initialOptionsState: OptionsState = {
|
||||||
@ -83,6 +84,7 @@ const initialOptionsState: OptionsState = {
|
|||||||
shouldPinOptionsPanel: true,
|
shouldPinOptionsPanel: true,
|
||||||
optionsPanelScrollPosition: 0,
|
optionsPanelScrollPosition: 0,
|
||||||
shouldHoldOptionsPanelOpen: false,
|
shouldHoldOptionsPanelOpen: false,
|
||||||
|
shouldLoopback: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const initialState: OptionsState = initialOptionsState;
|
const initialState: OptionsState = initialOptionsState;
|
||||||
@ -344,6 +346,9 @@ export const optionsSlice = createSlice({
|
|||||||
setShouldHoldOptionsPanelOpen: (state, action: PayloadAction<boolean>) => {
|
setShouldHoldOptionsPanelOpen: (state, action: PayloadAction<boolean>) => {
|
||||||
state.shouldHoldOptionsPanelOpen = action.payload;
|
state.shouldHoldOptionsPanelOpen = action.payload;
|
||||||
},
|
},
|
||||||
|
setShouldLoopback: (state, action: PayloadAction<boolean>) => {
|
||||||
|
state.shouldLoopback = action.payload;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -390,6 +395,7 @@ export const {
|
|||||||
setShouldPinOptionsPanel,
|
setShouldPinOptionsPanel,
|
||||||
setOptionsPanelScrollPosition,
|
setOptionsPanelScrollPosition,
|
||||||
setShouldHoldOptionsPanelOpen,
|
setShouldHoldOptionsPanelOpen,
|
||||||
|
setShouldLoopback,
|
||||||
} = optionsSlice.actions;
|
} = optionsSlice.actions;
|
||||||
|
|
||||||
export default optionsSlice.reducer;
|
export default optionsSlice.reducer;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { Tooltip } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import {
|
import {
|
||||||
FocusEvent,
|
FocusEvent,
|
||||||
@ -7,7 +8,7 @@ import {
|
|||||||
useEffect,
|
useEffect,
|
||||||
useRef,
|
useRef,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { BsPinAngleFill } from 'react-icons/bs';
|
import { BsPinAngle, BsPinAngleFill } from 'react-icons/bs';
|
||||||
import { CSSTransition } from 'react-transition-group';
|
import { CSSTransition } from 'react-transition-group';
|
||||||
import { RootState, useAppDispatch, useAppSelector } from '../../app/store';
|
import { RootState, useAppDispatch, useAppSelector } from '../../app/store';
|
||||||
import IAIIconButton from '../../common/components/IAIIconButton';
|
import IAIIconButton from '../../common/components/IAIIconButton';
|
||||||
@ -119,6 +120,16 @@ const InvokeOptionsPanel = (props: Props) => {
|
|||||||
!shouldPinOptionsPanel ? cancelCloseOptionsPanelTimer : undefined
|
!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
|
<div
|
||||||
className="options-panel"
|
className="options-panel"
|
||||||
ref={optionsPanelContainerRef}
|
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}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user