Adds Maintain Aspect Ratio checkbox to ImageGallery

This commit is contained in:
psychedelicious 2022-10-28 00:48:37 +11:00
parent 5cae8206f9
commit 38fd0668ba
7 changed files with 77 additions and 33 deletions

View File

@ -1,6 +1,8 @@
.invokeai__checkbox {
.chakra-checkbox__label {
margin-top: 1px;
color: var(--text-color-secondary);
font-size: 0.9rem;
}
.chakra-checkbox__control {

View File

@ -12,7 +12,6 @@
.hoverable-image-image {
width: 100%;
height: 100%;
object-fit: cover;
max-width: 100%;
max-height: 100%;
}

View File

@ -6,7 +6,7 @@ import {
Tooltip,
useToast,
} from '@chakra-ui/react';
import { RootState, useAppDispatch, useAppSelector } from '../../app/store';
import { useAppDispatch, useAppSelector } from '../../app/store';
import { setCurrentImage } from './gallerySlice';
import { FaCheck, FaTrashAlt } from 'react-icons/fa';
import DeleteImageModal from './DeleteImageModal';
@ -40,7 +40,7 @@ const memoEqualityCheck = (
*/
const HoverableImage = memo((props: HoverableImageProps) => {
const dispatch = useAppDispatch();
const { activeTabName } = useAppSelector(hoverableImageSelector);
const { activeTabName, galleryImageObjectFit } = useAppSelector(hoverableImageSelector);
const [isHovered, setIsHovered] = useState<boolean>(false);
@ -148,7 +148,7 @@ const HoverableImage = memo((props: HoverableImageProps) => {
>
<Image
className="hoverable-image-image"
objectFit="cover"
objectFit={galleryImageObjectFit}
rounded={'md'}
src={url}
loading={'lazy'}

View File

@ -62,10 +62,17 @@
}
}
.image-gallery-size-popover {
display: grid;
grid-template-columns: repeat(2, max-content);
column-gap: 0.5rem;
.image-gallery-settings-popover {
display: flex;
flex-direction: column;
row-gap: 0.5rem;
div {
display: flex;
column-gap: 0.5rem;
align-items: center;
justify-content: space-between;
}
}
h1 {

View File

@ -1,7 +1,7 @@
import { Button } from '@chakra-ui/button';
import { NumberSize, Resizable, Size } from 're-resizable';
import React, { useEffect, useRef, useState } from 'react';
import React, { ChangeEvent, useEffect, useRef, useState } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { MdClear, MdPhotoLibrary } from 'react-icons/md';
import { BsPinAngleFill } from 'react-icons/bs';
@ -12,6 +12,7 @@ import {
selectNextImage,
selectPrevImage,
setGalleryImageMinimumWidth,
setGalleryImageObjectFit,
setGalleryScrollPosition,
setShouldPinGallery,
} from './gallerySlice';
@ -25,6 +26,7 @@ import { FaWrench } from 'react-icons/fa';
import IAIPopover from '../../common/components/IAIPopover';
import IAISlider from '../../common/components/IAISlider';
import { BiReset } from 'react-icons/bi';
import IAICheckbox from '../../common/components/IAICheckbox';
export default function ImageGallery() {
const dispatch = useAppDispatch();
@ -40,6 +42,7 @@ export default function ImageGallery() {
galleryImageMinimumWidth,
galleryGridTemplateColumns,
activeTabName,
galleryImageObjectFit,
} = useAppSelector(imageGallerySelector);
const [gallerySize, setGallerySize] = useState<Size>({
@ -310,6 +313,7 @@ export default function ImageGallery() {
<IAIPopover
trigger="click"
hasArrow={activeTabName === 'inpainting' ? false : true}
// styleClass="image-gallery-settings-popover"
triggerComponent={
<IAIIconButton
size={'sm'}
@ -319,29 +323,47 @@ export default function ImageGallery() {
cursor={'pointer'}
/>
}
styleClass="image-gallery-size-popover"
>
<IAISlider
value={galleryImageMinimumWidth}
onChange={handleChangeGalleryImageMinimumWidth}
min={32}
max={256}
width={100}
label={'Image Size'}
formLabelProps={{ style: { fontSize: '0.9rem' } }}
sliderThumbTooltipProps={{
label: `${galleryImageMinimumWidth}px`,
}}
/>
<IAIIconButton
size={'sm'}
aria-label={'Reset'}
tooltip={'Reset Size'}
onClick={() => dispatch(setGalleryImageMinimumWidth(64))}
icon={<BiReset />}
data-selected={shouldPinGallery}
styleClass="image-gallery-icon-btn"
/>
<div className="image-gallery-settings-popover">
<div>
<IAISlider
value={galleryImageMinimumWidth}
onChange={handleChangeGalleryImageMinimumWidth}
min={32}
max={256}
width={100}
label={'Image Size'}
formLabelProps={{ style: { fontSize: '0.9rem' } }}
sliderThumbTooltipProps={{
label: `${galleryImageMinimumWidth}px`,
}}
/>
<IAIIconButton
size={'sm'}
aria-label={'Reset'}
tooltip={'Reset Size'}
onClick={() => dispatch(setGalleryImageMinimumWidth(64))}
icon={<BiReset />}
data-selected={shouldPinGallery}
styleClass="image-gallery-icon-btn"
/>
</div>
<div>
<IAICheckbox
label="Maintain Aspect Ratio"
isChecked={galleryImageObjectFit === 'contain'}
onChange={() =>
dispatch(
setGalleryImageObjectFit(
galleryImageObjectFit === 'contain'
? 'cover'
: 'contain'
)
)
}
/>
</div>
</div>
</IAIPopover>
<IAIIconButton

View File

@ -3,6 +3,8 @@ import type { PayloadAction } from '@reduxjs/toolkit';
import _, { clamp } from 'lodash';
import * as InvokeAI from '../../app/invokeai';
type GalleryImageObjectFitType = 'contain' | 'cover';
export interface GalleryState {
currentImage?: InvokeAI.Image;
currentImageUuid: string;
@ -15,6 +17,7 @@ export interface GalleryState {
shouldShowGallery: boolean;
galleryScrollPosition: number;
galleryImageMinimumWidth: number;
galleryImageObjectFit: GalleryImageObjectFitType;
}
const initialState: GalleryState = {
@ -25,6 +28,7 @@ const initialState: GalleryState = {
shouldShowGallery: true,
galleryScrollPosition: 0,
galleryImageMinimumWidth: 64,
galleryImageObjectFit: 'contain',
};
export const gallerySlice = createSlice({
@ -171,6 +175,12 @@ export const gallerySlice = createSlice({
setGalleryImageMinimumWidth: (state, action: PayloadAction<number>) => {
state.galleryImageMinimumWidth = action.payload;
},
setGalleryImageObjectFit: (
state,
action: PayloadAction<GalleryImageObjectFitType>
) => {
state.galleryImageObjectFit = action.payload;
},
},
});
@ -187,6 +197,7 @@ export const {
setShouldShowGallery,
setGalleryScrollPosition,
setGalleryImageMinimumWidth,
setGalleryImageObjectFit,
} = gallerySlice.actions;
export default gallerySlice.reducer;

View File

@ -15,6 +15,7 @@ export const imageGallerySelector = createSelector(
shouldShowGallery,
galleryScrollPosition,
galleryImageMinimumWidth,
galleryImageObjectFit,
} = gallery;
const { activeTab } = options;
@ -27,6 +28,7 @@ export const imageGallerySelector = createSelector(
shouldShowGallery,
galleryScrollPosition,
galleryImageMinimumWidth,
galleryImageObjectFit,
galleryGridTemplateColumns: `repeat(auto-fill, minmax(${galleryImageMinimumWidth}px, auto))`,
activeTabName: tabMap[activeTab],
};
@ -34,9 +36,10 @@ export const imageGallerySelector = createSelector(
);
export const hoverableImageSelector = createSelector(
(state: RootState) => state.options,
(options: OptionsState) => {
[(state: RootState) => state.options, (state: RootState) => state.gallery],
(options: OptionsState, gallery: GalleryState) => {
return {
galleryImageObjectFit: gallery.galleryImageObjectFit,
activeTabName: tabMap[options.activeTab],
};
}