From 0da36c12387098c7bebd288f70ece0b69d08219f Mon Sep 17 00:00:00 2001
From: psychedelicious <4822129+psychedelicious@users.noreply.github.com>
Date: Fri, 31 May 2024 18:07:39 +1000
Subject: [PATCH] feat(ui): use IAIDndImage for compare mode
---
.../ImageViewer/ImageComparison.tsx | 23 +++++-----
.../ImageViewer/ImageComparisonSideBySide.tsx | 46 ++++++++++---------
.../ImageViewer/ImageComparisonSlider.tsx | 27 ++++++-----
.../components/ImageViewer/ImageViewer.tsx | 9 ++--
4 files changed, 54 insertions(+), 51 deletions(-)
diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ImageComparison.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ImageComparison.tsx
index ab17c9ef4e..4377658348 100644
--- a/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ImageComparison.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ImageComparison.tsx
@@ -1,32 +1,31 @@
-import type { UseMeasureRect } from '@reactuses/core';
+import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { useAppSelector } from 'app/store/storeHooks';
import IAIDroppable from 'common/components/IAIDroppable';
import type { SelectForCompareDropData } from 'features/dnd/types';
import { ImageComparisonSideBySide } from 'features/gallery/components/ImageViewer/ImageComparisonSideBySide';
import { ImageComparisonSlider } from 'features/gallery/components/ImageViewer/ImageComparisonSlider';
+import { selectGallerySlice } from 'features/gallery/store/gallerySlice';
import type { PropsWithChildren } from 'react';
import { memo } from 'react';
-type Props = {
- containerSize: UseMeasureRect;
-};
+const selector = createMemoizedSelector(selectGallerySlice, (gallerySlice) => {
+ const firstImage = gallerySlice.selection.slice(-1)[0] ?? null;
+ const secondImage = gallerySlice.imageToCompare;
+ return { firstImage, secondImage };
+});
-export const ImageComparison = memo(({ containerSize }: Props) => {
+export const ImageComparison = memo(() => {
const comparisonMode = useAppSelector((s) => s.gallery.comparisonMode);
- const { firstImage, secondImage } = useAppSelector((s) => {
- const firstImage = s.gallery.selection.slice(-1)[0] ?? null;
- const secondImage = s.gallery.imageToCompare;
- return { firstImage, secondImage };
- });
+ const { firstImage, secondImage } = useAppSelector(selector);
if (!firstImage || !secondImage) {
- return No images to compare;
+ return Select an image to compare;
}
if (comparisonMode === 'slider') {
return (
-
+
);
}
diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ImageComparisonSideBySide.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ImageComparisonSideBySide.tsx
index edc2199aed..0f9636a61c 100644
--- a/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ImageComparisonSideBySide.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ImageComparisonSideBySide.tsx
@@ -1,7 +1,8 @@
-import { Flex, Image } from '@invoke-ai/ui-library';
+import { Flex } from '@invoke-ai/ui-library';
+import IAIDndImage from 'common/components/IAIDndImage';
+import type { ImageDraggableData } from 'features/dnd/types';
import ResizeHandle from 'features/ui/components/tabs/ResizeHandle';
-import { memo, useCallback, useRef } from 'react';
-import { useTranslation } from 'react-i18next';
+import { memo, useCallback, useMemo, useRef } from 'react';
import type { ImperativePanelGroupHandle } from 'react-resizable-panels';
import { Panel, PanelGroup } from 'react-resizable-panels';
import type { ImageDTO } from 'services/api/types';
@@ -18,7 +19,6 @@ type Props = {
};
export const ImageComparisonSideBySide = memo(({ firstImage, secondImage }: Props) => {
- const { t } = useTranslation();
const panelGroupRef = useRef(null);
const onDoubleClickHandle = useCallback(() => {
if (!panelGroupRef.current) {
@@ -27,21 +27,31 @@ export const ImageComparisonSideBySide = memo(({ firstImage, secondImage }: Prop
panelGroupRef.current.setLayout([50, 50]);
}, []);
+ const firstImageDraggableData = useMemo(
+ () => ({
+ id: 'image-compare-first-image',
+ payloadType: 'IMAGE_DTO',
+ payload: { imageDTO: firstImage },
+ }),
+ [firstImage]
+ );
+
+ const secondImageDraggableData = useMemo(
+ () => ({
+ id: 'image-compare-second-image',
+ payloadType: 'IMAGE_DTO',
+ payload: { imageDTO: secondImage },
+ }),
+ [secondImage]
+ );
+
return (
-
+
-
+
diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ImageComparisonSlider.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ImageComparisonSlider.tsx
index c9f169eeff..3eacacf6e5 100644
--- a/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ImageComparisonSlider.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ImageComparisonSlider.tsx
@@ -1,5 +1,5 @@
import { Box, Flex, Icon, Image, Text } from '@invoke-ai/ui-library';
-import type { UseMeasureRect } from '@reactuses/core';
+import { useMeasure } from '@reactuses/core';
import type { Dimensions } from 'features/canvas/store/canvasTypes';
import { STAGE_BG_DATAURL } from 'features/controlLayers/util/renderers';
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
@@ -25,13 +25,9 @@ type Props = {
* The second image to compare
*/
secondImage: ImageDTO;
- /**
- * The size of the container, required to fit the component correctly and manage aspect ratios.
- */
- containerSize: UseMeasureRect;
};
-export const ImageComparisonSlider = memo(({ firstImage, secondImage, containerSize }: Props) => {
+export const ImageComparisonSlider = memo(({ firstImage, secondImage }: Props) => {
const { t } = useTranslation();
// How far the handle is from the left - this will be a CSS calculation that takes into account the handle width
const [left, setLeft] = useState(HANDLE_LEFT_INITIAL_PX);
@@ -40,6 +36,7 @@ export const ImageComparisonSlider = memo(({ firstImage, secondImage, containerS
const handleRef = useRef(null);
// If the container size is not provided, use an internal ref and measure - can cause flicker on mount tho
const containerRef = useRef(null);
+ const [containerSize] = useMeasure(containerRef);
// To keep things smooth, we use RAF to update the handle position & gate it to 60fps
const rafRef = useRef(null);
const lastMoveTimeRef = useRef(0);
@@ -94,13 +91,13 @@ export const ImageComparisonSlider = memo(({ firstImage, secondImage, containerS
const targetAspectRatio = containerSize.width / containerSize.height;
const imageAspectRatio = firstImage.width / firstImage.height;
+ let width: number;
+ let height: number;
+
if (firstImage.width <= containerSize.width && firstImage.height <= containerSize.height) {
return { width: firstImage.width, height: firstImage.height };
}
- let width: number;
- let height: number;
-
if (imageAspectRatio > targetAspectRatio) {
// Image is wider than container's aspect ratio
width = containerSize.width;
@@ -123,7 +120,16 @@ export const ImageComparisonSlider = memo(({ firstImage, secondImage, containerS
);
return (
-
+
{
const { viewerMode, onToggle, openEditor } = useImageViewer();
const activeTabName = useAppSelector(activeTabNameSelector);
const isViewerEnabled = useMemo(() => VIEWER_ENABLED_TABS.includes(activeTabName), [activeTabName]);
- const containerRef = useRef(null);
- const [containerSize] = useMeasure(containerRef);
const shouldShowViewer = useMemo(() => {
if (!isViewerEnabled) {
return false;
@@ -70,9 +67,9 @@ export const ImageViewer = memo(() => {
-
+
{viewerMode === 'view' && }
- {viewerMode === 'compare' && }
+ {viewerMode === 'compare' && }
);