mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Merge remote-tracking branch 'origin/user-image-uploads' into inpainting-rebase
This commit is contained in:
commit
0b046c95ef
@ -17,7 +17,7 @@ interface Props extends IconButtonProps {
|
|||||||
const IAIIconButton = (props: Props) => {
|
const IAIIconButton = (props: Props) => {
|
||||||
const {
|
const {
|
||||||
tooltip = '',
|
tooltip = '',
|
||||||
tooltipPlacement = 'top',
|
tooltipPlacement = 'bottom',
|
||||||
styleClass,
|
styleClass,
|
||||||
onClick,
|
onClick,
|
||||||
cursor,
|
cursor,
|
||||||
|
@ -24,7 +24,14 @@
|
|||||||
.image-upload-child {
|
.image-upload-child {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
row-gap: 3rem;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 4rem !important;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
font-size: 1.2rem !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Button, Heading, useToast } from '@chakra-ui/react';
|
import { Heading, useToast } from '@chakra-ui/react';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { FileRejection } from 'react-dropzone';
|
import { FileRejection } from 'react-dropzone';
|
||||||
import { FaUpload } from 'react-icons/fa';
|
import { FaUpload } from 'react-icons/fa';
|
||||||
@ -42,7 +42,11 @@ export default function InvokeImageUploader(props: InvokeImageUploaderProps) {
|
|||||||
<ImageUploader
|
<ImageUploader
|
||||||
fileAcceptedCallback={fileAcceptedCallback}
|
fileAcceptedCallback={fileAcceptedCallback}
|
||||||
fileRejectionCallback={fileRejectionCallback}
|
fileRejectionCallback={fileRejectionCallback}
|
||||||
styleClass={`${styleClass} image-upload-child-wrapper`}
|
styleClass={
|
||||||
|
styleClass
|
||||||
|
? `${styleClass} image-upload-child-wrapper`
|
||||||
|
: `image-upload-child-wrapper`
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<div className="image-upload-child">
|
<div className="image-upload-child">
|
||||||
<FaUpload size={'7rem'} />
|
<FaUpload size={'7rem'} />
|
||||||
|
@ -140,7 +140,8 @@ const CurrentImageButtons = ({ image }: CurrentImageButtonsProps) => {
|
|||||||
[image]
|
[image]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleClickUseSeed = () => image.metadata && dispatch(setSeed(image.metadata.image.seed));
|
const handleClickUseSeed = () =>
|
||||||
|
image.metadata && dispatch(setSeed(image.metadata.image.seed));
|
||||||
useHotkeys(
|
useHotkeys(
|
||||||
's',
|
's',
|
||||||
() => {
|
() => {
|
||||||
|
@ -18,6 +18,10 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
column-gap: 0.5rem;
|
column-gap: 0.5rem;
|
||||||
|
|
||||||
|
.chakra-popover__popper {
|
||||||
|
z-index: 11;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.current-image-viewer {
|
.current-image-viewer {
|
||||||
|
@ -89,10 +89,12 @@
|
|||||||
|
|
||||||
.image-gallery-container-placeholder {
|
.image-gallery-container-placeholder {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
background-color: var(--background-color-secondary);
|
background-color: var(--background-color-secondary);
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
padding: 2rem 0;
|
padding: 2rem;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
p {
|
p {
|
||||||
color: var(--subtext-color-bright);
|
color: var(--subtext-color-bright);
|
||||||
|
@ -21,7 +21,7 @@ import {
|
|||||||
} from './gallerySlice';
|
} from './gallerySlice';
|
||||||
import HoverableImage from './HoverableImage';
|
import HoverableImage from './HoverableImage';
|
||||||
import { setShouldShowGallery } from '../gallery/gallerySlice';
|
import { setShouldShowGallery } from '../gallery/gallerySlice';
|
||||||
import { ButtonGroup, Spacer, useToast } from '@chakra-ui/react';
|
import { ButtonGroup, useToast } from '@chakra-ui/react';
|
||||||
import { CSSTransition } from 'react-transition-group';
|
import { CSSTransition } from 'react-transition-group';
|
||||||
import { Direction } from 're-resizable/lib/resizer';
|
import { Direction } from 're-resizable/lib/resizer';
|
||||||
import { imageGallerySelector } from './gallerySliceSelectors';
|
import { imageGallerySelector } from './gallerySliceSelectors';
|
||||||
@ -77,6 +77,13 @@ export default function ImageGallery() {
|
|||||||
setGallerySize((prevSize) => {
|
setGallerySize((prevSize) => {
|
||||||
return { ...prevSize, width: Math.min(Number(prevSize.width), 200) };
|
return { ...prevSize, width: Math.min(Number(prevSize.width), 200) };
|
||||||
});
|
});
|
||||||
|
} else if (activeTabName === 'img2img' && shouldPinGallery) {
|
||||||
|
setGalleryMaxSize((prevSize) => {
|
||||||
|
return { ...prevSize, width: '490', height: '100%' };
|
||||||
|
});
|
||||||
|
setGallerySize((prevSize) => {
|
||||||
|
return { ...prevSize, width: Math.min(Number(prevSize.width), 490) };
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
setGalleryMaxSize((prevSize) => {
|
setGalleryMaxSize((prevSize) => {
|
||||||
return { ...prevSize, width: '590', height: '100%' };
|
return { ...prevSize, width: '590', height: '100%' };
|
||||||
@ -319,12 +326,6 @@ export default function ImageGallery() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="image-gallery-header">
|
<div className="image-gallery-header">
|
||||||
{/*{activeTabName !== 'inpainting' ? (
|
|
||||||
<>
|
|
||||||
<h1>Your Invocations</h1>
|
|
||||||
<Spacer />
|
|
||||||
</>
|
|
||||||
) : null}*/}
|
|
||||||
<div>
|
<div>
|
||||||
<ButtonGroup
|
<ButtonGroup
|
||||||
size="sm"
|
size="sm"
|
||||||
@ -351,6 +352,7 @@ export default function ImageGallery() {
|
|||||||
<IAIPopover
|
<IAIPopover
|
||||||
trigger="hover"
|
trigger="hover"
|
||||||
hasArrow={activeTabName === 'inpainting' ? false : true}
|
hasArrow={activeTabName === 'inpainting' ? false : true}
|
||||||
|
placement={'left'}
|
||||||
triggerComponent={
|
triggerComponent={
|
||||||
<IAIIconButton
|
<IAIIconButton
|
||||||
size={'sm'}
|
size={'sm'}
|
||||||
|
@ -33,7 +33,7 @@ const ModelListItem = (props: ModelListItemProps) => {
|
|||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div className="model-list-item">
|
<div className="model-list-item">
|
||||||
<Tooltip label={description} hasArrow placement="top">
|
<Tooltip label={description} hasArrow placement="bottom">
|
||||||
<div className="model-list-item-name">{name}</div>
|
<div className="model-list-item-name">{name}</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Spacer />
|
<Spacer />
|
||||||
|
@ -49,7 +49,6 @@
|
|||||||
img {
|
img {
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
width: auto;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ const ImageToImageDisplay = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="workarea-split-view">
|
<div className="workarea-split-view">
|
||||||
<div className="workarea-split-view-left">{imageToImageComponent} </div>
|
<div className="workarea-split-view-left">{imageToImageComponent}</div>
|
||||||
{currentImage && (
|
{currentImage && (
|
||||||
<div className="workarea-split-view-right">
|
<div className="workarea-split-view-right">
|
||||||
<CurrentImageDisplay />
|
<CurrentImageDisplay />
|
||||||
|
@ -19,6 +19,16 @@
|
|||||||
column-gap: 0.5rem;
|
column-gap: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.inpainting-button-dropdown {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
row-gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inpainting-color-picker {
|
||||||
|
margin-left: 1rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
.inpainting-slider-numberinput {
|
.inpainting-slider-numberinput {
|
||||||
display: flex;
|
display: flex;
|
||||||
column-gap: 1rem;
|
column-gap: 1rem;
|
||||||
@ -80,10 +90,4 @@
|
|||||||
inset: 0 auto auto -75px !important;
|
inset: 0 auto auto -75px !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.current-image-options {
|
|
||||||
.chakra-popover__popper {
|
|
||||||
z-index: 11;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ import { useToast } from '@chakra-ui/react';
|
|||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import {
|
import {
|
||||||
FaEraser,
|
FaEraser,
|
||||||
|
FaMask,
|
||||||
FaPaintBrush,
|
FaPaintBrush,
|
||||||
FaPalette,
|
FaPalette,
|
||||||
FaPlus,
|
FaPlus,
|
||||||
@ -36,6 +37,7 @@ import IAIPopover from '../../../common/components/IAIPopover';
|
|||||||
import IAIColorPicker from '../../../common/components/IAIColorPicker';
|
import IAIColorPicker from '../../../common/components/IAIColorPicker';
|
||||||
import { RgbaColor } from 'react-colorful';
|
import { RgbaColor } from 'react-colorful';
|
||||||
import { setShowDualDisplay } from '../../options/optionsSlice';
|
import { setShowDualDisplay } from '../../options/optionsSlice';
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
const InpaintingControls = () => {
|
const InpaintingControls = () => {
|
||||||
const {
|
const {
|
||||||
@ -54,6 +56,9 @@ const InpaintingControls = () => {
|
|||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
|
// Button State Controllers
|
||||||
|
const [maskOptionsOpen, setMaskOptionsOpen] = useState<boolean>(false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hotkeys
|
* Hotkeys
|
||||||
*/
|
*/
|
||||||
@ -334,39 +339,71 @@ const InpaintingControls = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="inpainting-buttons-group">
|
<div className="inpainting-buttons-group">
|
||||||
<IAIPopover
|
<IAIPopover
|
||||||
trigger="hover"
|
trigger="click"
|
||||||
|
onOpen={() => setMaskOptionsOpen(true)}
|
||||||
|
onClose={() => setMaskOptionsOpen(false)}
|
||||||
triggerComponent={
|
triggerComponent={
|
||||||
<IAIIconButton
|
<IAIIconButton
|
||||||
aria-label="Mask Color"
|
aria-label="Mask Options"
|
||||||
tooltip="Mask Color"
|
tooltip="Mask Options"
|
||||||
icon={<FaPalette />}
|
icon={<FaMask />}
|
||||||
isDisabled={!shouldShowMask}
|
|
||||||
cursor={'pointer'}
|
cursor={'pointer'}
|
||||||
|
isDisabled={isMaskEmpty}
|
||||||
|
data-selected={maskOptionsOpen}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<IAIColorPicker color={maskColor} onChange={handleChangeMaskColor} />
|
<div className="inpainting-button-dropdown">
|
||||||
|
<IAIIconButton
|
||||||
|
aria-label="Hide/Show Mask (H)"
|
||||||
|
tooltip="Hide/Show Mask (H)"
|
||||||
|
data-selected={!shouldShowMask}
|
||||||
|
icon={
|
||||||
|
shouldShowMask ? <BiShow size={22} /> : <BiHide size={22} />
|
||||||
|
}
|
||||||
|
onClick={handleToggleShouldShowMask}
|
||||||
|
/>
|
||||||
|
<IAIIconButton
|
||||||
|
tooltip="Invert Mask Display (Shift+M)"
|
||||||
|
aria-label="Invert Mask Display (Shift+M)"
|
||||||
|
data-selected={shouldInvertMask}
|
||||||
|
icon={
|
||||||
|
shouldInvertMask ? (
|
||||||
|
<MdInvertColors size={22} />
|
||||||
|
) : (
|
||||||
|
<MdInvertColorsOff size={22} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
onClick={handleToggleShouldInvertMask}
|
||||||
|
isDisabled={!shouldShowMask}
|
||||||
|
/>
|
||||||
|
<IAIPopover
|
||||||
|
trigger="hover"
|
||||||
|
placement="right"
|
||||||
|
styleClass="inpainting-color-picker"
|
||||||
|
triggerComponent={
|
||||||
|
<IAIIconButton
|
||||||
|
aria-label="Mask Color"
|
||||||
|
tooltip="Mask Color"
|
||||||
|
icon={<FaPalette />}
|
||||||
|
isDisabled={!shouldShowMask}
|
||||||
|
cursor={'pointer'}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<IAIColorPicker
|
||||||
|
color={maskColor}
|
||||||
|
onChange={handleChangeMaskColor}
|
||||||
|
/>
|
||||||
|
</IAIPopover>
|
||||||
|
</div>
|
||||||
</IAIPopover>
|
</IAIPopover>
|
||||||
<IAIIconButton
|
<IAIIconButton
|
||||||
aria-label="Hide/Show Mask (H)"
|
aria-label="Clear Mask (Shift+C)"
|
||||||
tooltip="Hide/Show Mask (H)"
|
tooltip="Clear Mask (Shift+C)"
|
||||||
data-selected={!shouldShowMask}
|
icon={<FaPlus size={18} style={{ transform: 'rotate(45deg)' }} />}
|
||||||
icon={shouldShowMask ? <BiShow size={22} /> : <BiHide size={22} />}
|
onClick={handleClearMask}
|
||||||
onClick={handleToggleShouldShowMask}
|
isDisabled={isMaskEmpty || !shouldShowMask}
|
||||||
/>
|
|
||||||
<IAIIconButton
|
|
||||||
tooltip="Invert Mask Display (Shift+M)"
|
|
||||||
aria-label="Invert Mask Display (Shift+M)"
|
|
||||||
data-selected={shouldInvertMask}
|
|
||||||
icon={
|
|
||||||
shouldInvertMask ? (
|
|
||||||
<MdInvertColors size={22} />
|
|
||||||
) : (
|
|
||||||
<MdInvertColorsOff size={22} />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
onClick={handleToggleShouldInvertMask}
|
|
||||||
isDisabled={!shouldShowMask}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="inpainting-buttons-group">
|
<div className="inpainting-buttons-group">
|
||||||
@ -384,28 +421,23 @@ const InpaintingControls = () => {
|
|||||||
onClick={handleRedo}
|
onClick={handleRedo}
|
||||||
isDisabled={!canRedo || !shouldShowMask}
|
isDisabled={!canRedo || !shouldShowMask}
|
||||||
/>
|
/>
|
||||||
<IAIIconButton
|
</div>
|
||||||
aria-label="Clear Mask Canvas (Shift + C)"
|
|
||||||
tooltip="Clear Mask Canvas (Shift + C)"
|
<div className="inpainting-buttons-group">
|
||||||
icon={<FaPlus size={18} style={{ transform: 'rotate(45deg)' }} />}
|
|
||||||
onClick={handleClearMask}
|
|
||||||
isDisabled={isMaskEmpty || !shouldShowMask}
|
|
||||||
/>
|
|
||||||
<IAIIconButton
|
<IAIIconButton
|
||||||
aria-label="Clear Image"
|
aria-label="Clear Image"
|
||||||
tooltip="Clear Image"
|
tooltip="Clear Image"
|
||||||
icon={<FaTrash size={18} />}
|
icon={<FaTrash size={16} />}
|
||||||
onClick={handleClearImage}
|
onClick={handleClearImage}
|
||||||
// isDisabled={}
|
|
||||||
/>
|
|
||||||
<IAIIconButton
|
|
||||||
aria-label="Split Layout (Shift+J)"
|
|
||||||
tooltip="Split Layout (Shift+J)"
|
|
||||||
icon={<VscSplitHorizontal />}
|
|
||||||
data-selected={showDualDisplay}
|
|
||||||
onClick={handleDualDisplay}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<IAIIconButton
|
||||||
|
aria-label="Split Layout (Shift+J)"
|
||||||
|
tooltip="Split Layout (Shift+J)"
|
||||||
|
icon={<VscSplitHorizontal />}
|
||||||
|
data-selected={showDualDisplay}
|
||||||
|
onClick={handleDualDisplay}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -4,7 +4,10 @@ import InvokeWorkarea from '../InvokeWorkarea';
|
|||||||
|
|
||||||
export default function InpaintingWorkarea() {
|
export default function InpaintingWorkarea() {
|
||||||
return (
|
return (
|
||||||
<InvokeWorkarea optionsPanel={<InpaintingPanel />}>
|
<InvokeWorkarea
|
||||||
|
optionsPanel={<InpaintingPanel />}
|
||||||
|
styleClass="inpainting-workarea-overrides"
|
||||||
|
>
|
||||||
<InpaintingDisplay />
|
<InpaintingDisplay />
|
||||||
</InvokeWorkarea>
|
</InvokeWorkarea>
|
||||||
);
|
);
|
||||||
|
@ -42,13 +42,5 @@
|
|||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.workarea-split-view-left {
|
|
||||||
padding-right: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.workarea-split-view-right {
|
|
||||||
padding-left: 0.5rem;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,16 +6,21 @@ import ShowHideGalleryButton from '../gallery/ShowHideGalleryButton';
|
|||||||
type InvokeWorkareaProps = {
|
type InvokeWorkareaProps = {
|
||||||
optionsPanel: ReactNode;
|
optionsPanel: ReactNode;
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
|
styleClass?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const InvokeWorkarea = (props: InvokeWorkareaProps) => {
|
const InvokeWorkarea = (props: InvokeWorkareaProps) => {
|
||||||
const { optionsPanel, children } = props;
|
const { optionsPanel, children, styleClass } = props;
|
||||||
|
|
||||||
const { shouldShowGallery, shouldHoldGalleryOpen, shouldPinGallery } =
|
const { shouldShowGallery, shouldHoldGalleryOpen, shouldPinGallery } =
|
||||||
useAppSelector((state: RootState) => state.gallery);
|
useAppSelector((state: RootState) => state.gallery);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="workarea-wrapper">
|
<div
|
||||||
|
className={
|
||||||
|
styleClass ? `workarea-wrapper ${styleClass}` : `workarea-wrapper`
|
||||||
|
}
|
||||||
|
>
|
||||||
<div className="workarea-main">
|
<div className="workarea-main">
|
||||||
<div className="workarea-options-panel">{optionsPanel}</div>
|
<div className="workarea-options-panel">{optionsPanel}</div>
|
||||||
{children}
|
{children}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user