NEWONE1
/
invokeai
/frontend
/web
/src
/features
/gallery
/components
/ImageViewer
/CompareToolbar.tsx
import { | |
Button, | |
ButtonGroup, | |
Flex, | |
Icon, | |
IconButton, | |
Kbd, | |
ListItem, | |
Tooltip, | |
UnorderedList, | |
} from '@invoke-ai/ui-library'; | |
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; | |
import { selectComparisonFit, selectComparisonMode } from 'features/gallery/store/gallerySelectors'; | |
import { | |
comparedImagesSwapped, | |
comparisonFitChanged, | |
comparisonModeChanged, | |
comparisonModeCycled, | |
imageToCompareChanged, | |
} from 'features/gallery/store/gallerySlice'; | |
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData'; | |
import { memo, useCallback } from 'react'; | |
import { useHotkeys } from 'react-hotkeys-hook'; | |
import { Trans, useTranslation } from 'react-i18next'; | |
import { PiArrowsLeftRightBold, PiArrowsOutBold, PiQuestion } from 'react-icons/pi'; | |
export const CompareToolbar = memo(() => { | |
const { t } = useTranslation(); | |
const dispatch = useAppDispatch(); | |
const comparisonMode = useAppSelector(selectComparisonMode); | |
const comparisonFit = useAppSelector(selectComparisonFit); | |
const setComparisonModeSlider = useCallback(() => { | |
dispatch(comparisonModeChanged('slider')); | |
}, [dispatch]); | |
const setComparisonModeSideBySide = useCallback(() => { | |
dispatch(comparisonModeChanged('side-by-side')); | |
}, [dispatch]); | |
const setComparisonModeHover = useCallback(() => { | |
dispatch(comparisonModeChanged('hover')); | |
}, [dispatch]); | |
const swapImages = useCallback(() => { | |
dispatch(comparedImagesSwapped()); | |
}, [dispatch]); | |
useRegisteredHotkeys({ | |
id: 'swapImages', | |
category: 'viewer', | |
callback: swapImages, | |
dependencies: [swapImages], | |
}); | |
const toggleComparisonFit = useCallback(() => { | |
dispatch(comparisonFitChanged(comparisonFit === 'contain' ? 'fill' : 'contain')); | |
}, [dispatch, comparisonFit]); | |
const exitCompare = useCallback(() => { | |
dispatch(imageToCompareChanged(null)); | |
}, [dispatch]); | |
useHotkeys('esc', exitCompare, [exitCompare]); | |
const nextMode = useCallback(() => { | |
dispatch(comparisonModeCycled()); | |
}, [dispatch]); | |
useRegisteredHotkeys({ id: 'nextComparisonMode', category: 'viewer', callback: nextMode, dependencies: [nextMode] }); | |
return ( | |
<Flex w="full" px={2} gap={2} bg="base.750" borderTopRadius="base" h={12}> | |
<Flex flex={1} justifyContent="center"> | |
<Flex marginInlineEnd="auto" alignItems="center"> | |
<IconButton | |
icon={<PiArrowsLeftRightBold />} | |
aria-label={`${t('gallery.swapImages')} (C)`} | |
tooltip={`${t('gallery.swapImages')} (C)`} | |
onClick={swapImages} | |
variant="link" | |
alignSelf="stretch" | |
/> | |
{comparisonMode !== 'side-by-side' && ( | |
<IconButton | |
aria-label={t('gallery.stretchToFit')} | |
tooltip={t('gallery.stretchToFit')} | |
onClick={toggleComparisonFit} | |
colorScheme={comparisonFit === 'fill' ? 'invokeBlue' : 'base'} | |
variant="link" | |
alignSelf="stretch" | |
icon={<PiArrowsOutBold />} | |
/> | |
)} | |
</Flex> | |
</Flex> | |
<Flex flex={1} justifyContent="center"> | |
<ButtonGroup variant="outline" alignItems="center"> | |
<Button | |
flexShrink={0} | |
onClick={setComparisonModeSlider} | |
colorScheme={comparisonMode === 'slider' ? 'invokeBlue' : 'base'} | |
> | |
{t('gallery.slider')} | |
</Button> | |
<Button | |
flexShrink={0} | |
onClick={setComparisonModeSideBySide} | |
colorScheme={comparisonMode === 'side-by-side' ? 'invokeBlue' : 'base'} | |
> | |
{t('gallery.sideBySide')} | |
</Button> | |
<Button | |
flexShrink={0} | |
onClick={setComparisonModeHover} | |
colorScheme={comparisonMode === 'hover' ? 'invokeBlue' : 'base'} | |
> | |
{t('gallery.hover')} | |
</Button> | |
</ButtonGroup> | |
</Flex> | |
<Flex flex={1} justifyContent="center"> | |
<Flex gap={2} marginInlineStart="auto" alignItems="center"> | |
<Tooltip label={<CompareHelp />}> | |
<Flex alignItems="center"> | |
<Icon boxSize={6} color="base.300" as={PiQuestion} lineHeight={0} /> | |
</Flex> | |
</Tooltip> | |
<Button | |
variant="link" | |
alignSelf="stretch" | |
px={2} | |
aria-label={`${t('gallery.exitCompare')} (Esc)`} | |
tooltip={`${t('gallery.exitCompare')} (Esc)`} | |
onClick={exitCompare} | |
> | |
{t('gallery.exitCompare')} | |
</Button> | |
</Flex> | |
</Flex> | |
</Flex> | |
); | |
}); | |
CompareToolbar.displayName = 'CompareToolbar'; | |
const CompareHelp = () => { | |
return ( | |
<UnorderedList> | |
<ListItem> | |
<Trans i18nKey="gallery.compareHelp1" components={{ Kbd: <Kbd /> }}></Trans> | |
</ListItem> | |
<ListItem> | |
<Trans i18nKey="gallery.compareHelp2" components={{ Kbd: <Kbd /> }}></Trans> | |
</ListItem> | |
<ListItem> | |
<Trans i18nKey="gallery.compareHelp3" components={{ Kbd: <Kbd /> }}></Trans> | |
</ListItem> | |
<ListItem> | |
<Trans i18nKey="gallery.compareHelp4" components={{ Kbd: <Kbd /> }}></Trans> | |
</ListItem> | |
</UnorderedList> | |
); | |
}; | |