File size: 4,056 Bytes
8a37e0a |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
import { ButtonGroup, Flex, Icon, IconButton, spinAnimation, Tooltip, useShiftModifier } from '@invoke-ai/ui-library';
import { useAppSelector } from 'app/store/storeHooks';
import { ToolChooser } from 'features/controlLayers/components/Tool/ToolChooser';
import { CanvasManagerProviderGate } from 'features/controlLayers/contexts/CanvasManagerProviderGate';
import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
import { useClearQueue } from 'features/queue/components/ClearQueueConfirmationAlertDialog';
import { QueueButtonTooltip } from 'features/queue/components/QueueButtonTooltip';
import { useCancelCurrentQueueItem } from 'features/queue/hooks/useCancelCurrentQueueItem';
import { useInvoke } from 'features/queue/hooks/useInvoke';
import type { UsePanelReturn } from 'features/ui/hooks/usePanel';
import { selectActiveTab } from 'features/ui/store/uiSelectors';
import { memo, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import {
PiCircleNotchBold,
PiLightningFill,
PiSlidersHorizontalBold,
PiSparkleFill,
PiTrashSimpleBold,
PiXBold,
} from 'react-icons/pi';
import { useGetQueueStatusQuery } from 'services/api/endpoints/queue';
type Props = {
panelApi: UsePanelReturn;
};
const FloatingSidePanelButtons = (props: Props) => {
const { t } = useTranslation();
const queue = useInvoke();
const shift = useShiftModifier();
const tab = useAppSelector(selectActiveTab);
const imageViewer = useImageViewer();
const clearQueue = useClearQueue();
const { data: queueStatus } = useGetQueueStatusQuery();
const cancelCurrent = useCancelCurrentQueueItem();
const queueButtonIcon = useMemo(() => {
const isProcessing = (queueStatus?.queue.in_progress ?? 0) > 0;
if (!queue.isDisabled && isProcessing) {
return <Icon boxSize={6} as={PiCircleNotchBold} animation={spinAnimation} />;
}
if (shift) {
return <PiLightningFill />;
}
return <PiSparkleFill />;
}, [queue.isDisabled, queueStatus?.queue.in_progress, shift]);
return (
<Flex pos="absolute" transform="translate(0, -50%)" top="50%" insetInlineStart={2} direction="column" gap={2}>
{tab === 'canvas' && !imageViewer.isOpen && (
<CanvasManagerProviderGate>
<ToolChooser />
</CanvasManagerProviderGate>
)}
<ButtonGroup orientation="vertical" h={48}>
<Tooltip label={t('accessibility.toggleLeftPanel')} placement="end">
<IconButton
aria-label={t('accessibility.toggleLeftPanel')}
onClick={props.panelApi.toggle}
icon={<PiSlidersHorizontalBold />}
flexGrow={1}
/>
</Tooltip>
<QueueButtonTooltip prepend={shift} placement="end">
<IconButton
aria-label={t('queue.queueBack')}
onClick={shift ? queue.queueFront : queue.queueBack}
isLoading={queue.isLoading}
isDisabled={queue.isDisabled}
icon={queueButtonIcon}
colorScheme="invokeYellow"
flexGrow={1}
/>
</QueueButtonTooltip>
<Tooltip label={t('queue.cancelTooltip')} placement="end">
<IconButton
isDisabled={cancelCurrent.isDisabled}
isLoading={cancelCurrent.isLoading}
aria-label={t('queue.cancelTooltip')}
icon={<PiXBold />}
onClick={cancelCurrent.cancelQueueItem}
colorScheme="error"
flexGrow={1}
/>
</Tooltip>
<Tooltip label={t('queue.clearTooltip')} placement="end">
<IconButton
isDisabled={clearQueue.isDisabled}
isLoading={clearQueue.isLoading}
aria-label={t('queue.clearTooltip')}
icon={<PiTrashSimpleBold />}
colorScheme="error"
onClick={clearQueue.openDialog}
data-testid={t('queue.clear')}
flexGrow={1}
/>
</Tooltip>
</ButtonGroup>
</Flex>
);
};
export default memo(FloatingSidePanelButtons);
|