mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-02-15 23:05:11 -05:00
feat(ui): copy layer to clipboard
This commit is contained in:
committed by
psychedelicious
parent
bc683f955d
commit
8cd78f7f34
@@ -1,5 +1,6 @@
|
||||
import { MenuGroup } from '@invoke-ai/ui-library';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { CanvasEntityMenuItemsCopy } from 'features/controlLayers/components/common/CanvasEntityMenuItemsCopy';
|
||||
import { CanvasEntityMenuItemsDelete } from 'features/controlLayers/components/common/CanvasEntityMenuItemsDelete';
|
||||
import { CanvasEntityMenuItemsFilter } from 'features/controlLayers/components/common/CanvasEntityMenuItemsFilter';
|
||||
import { CanvasEntityMenuItemsTransform } from 'features/controlLayers/components/common/CanvasEntityMenuItemsTransform';
|
||||
@@ -20,6 +21,7 @@ const CanvasContextMenuSelectedEntityMenuItemsContent = memo(() => {
|
||||
<MenuGroup title={title}>
|
||||
{isFilterableEntityIdentifier(entityIdentifier) && <CanvasEntityMenuItemsFilter />}
|
||||
{isTransformableEntityIdentifier(entityIdentifier) && <CanvasEntityMenuItemsTransform />}
|
||||
<CanvasEntityMenuItemsCopy />
|
||||
<CanvasEntityMenuItemsDelete />
|
||||
</MenuGroup>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import { IconButton } from '@invoke-ai/ui-library';
|
||||
import { useEntityAdapterSafe } from 'features/controlLayers/contexts/EntityAdapterContext';
|
||||
import { useEntityIdentifierContext } from 'features/controlLayers/contexts/EntityIdentifierContext';
|
||||
import { useCanvasIsBusy } from 'features/controlLayers/hooks/useCanvasIsBusy';
|
||||
import { useCopyLayerToClipboard } from 'features/controlLayers/hooks/useCopyLayerToClipboard';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiCopyBold } from 'react-icons/pi';
|
||||
|
||||
export const CanvasEntityCopyToClipboard = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const entityIdentifier = useEntityIdentifierContext();
|
||||
const adapter = useEntityAdapterSafe(entityIdentifier);
|
||||
const isBusy = useCanvasIsBusy();
|
||||
const copyLayerToClipboard = useCopyLayerToClipboard();
|
||||
const onClick = useCallback(() => {
|
||||
copyLayerToClipboard(adapter);
|
||||
}, [copyLayerToClipboard, adapter]);
|
||||
|
||||
return (
|
||||
<IconButton
|
||||
size="sm"
|
||||
aria-label={t('unifiedCanvas.copyToClipboard')}
|
||||
tooltip={t('unifiedCanvas.copyToClipboard')}
|
||||
variant="link"
|
||||
alignSelf="stretch"
|
||||
icon={<PiCopyBold />}
|
||||
onClick={onClick}
|
||||
isDisabled={isBusy}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
CanvasEntityCopyToClipboard.displayName = 'CanvasEntityCopyToClipboard';
|
||||
@@ -6,11 +6,14 @@ import { CanvasEntityIsLockedToggle } from 'features/controlLayers/components/co
|
||||
import { useEntityIdentifierContext } from 'features/controlLayers/contexts/EntityIdentifierContext';
|
||||
import { memo } from 'react';
|
||||
|
||||
import { CanvasEntityCopyToClipboard } from './CanvasEntityCopyToClipboard';
|
||||
|
||||
export const CanvasEntityHeaderCommonActions = memo(() => {
|
||||
const entityIdentifier = useEntityIdentifierContext();
|
||||
|
||||
return (
|
||||
<Flex alignSelf="stretch">
|
||||
<CanvasEntityCopyToClipboard />
|
||||
<CanvasEntityIsBookmarkedForQuickSwitchToggle />
|
||||
{entityIdentifier.type !== 'reference_image' && <CanvasEntityIsLockedToggle />}
|
||||
<CanvasEntityEnabledToggle />
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { MenuItem } from '@invoke-ai/ui-library';
|
||||
import { useEntityAdapterSafe } from 'features/controlLayers/contexts/EntityAdapterContext';
|
||||
import { useEntityIdentifierContext } from 'features/controlLayers/contexts/EntityIdentifierContext';
|
||||
import { useCopyLayerToClipboard } from 'features/controlLayers/hooks/useCopyLayerToClipboard';
|
||||
import { useIsEntityInteractable } from 'features/controlLayers/hooks/useEntityIsInteractable';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiCopyBold } from 'react-icons/pi';
|
||||
|
||||
export const CanvasEntityMenuItemsCopy = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const entityIdentifier = useEntityIdentifierContext();
|
||||
const adapter = useEntityAdapterSafe(entityIdentifier);
|
||||
const isInteractable = useIsEntityInteractable(entityIdentifier);
|
||||
const copyLayerToClipboard = useCopyLayerToClipboard();
|
||||
|
||||
const onClick = useCallback(() => {
|
||||
copyLayerToClipboard(adapter);
|
||||
}, [copyLayerToClipboard, adapter]);
|
||||
|
||||
return (
|
||||
<MenuItem onClick={onClick} icon={<PiCopyBold />} isDisabled={!isInteractable}>
|
||||
{t('controlLayers.copyToClipboard')}
|
||||
</MenuItem>
|
||||
);
|
||||
});
|
||||
|
||||
CanvasEntityMenuItemsCopy.displayName = 'CanvasEntityMenuItemsCopy';
|
||||
@@ -0,0 +1,44 @@
|
||||
import type { CanvasEntityAdapterControlLayer } from 'features/controlLayers/konva/CanvasEntity/CanvasEntityAdapterControlLayer';
|
||||
import type { CanvasEntityAdapterInpaintMask } from 'features/controlLayers/konva/CanvasEntity/CanvasEntityAdapterInpaintMask';
|
||||
import type { CanvasEntityAdapterRasterLayer } from 'features/controlLayers/konva/CanvasEntity/CanvasEntityAdapterRasterLayer';
|
||||
import type { CanvasEntityAdapterRegionalGuidance } from 'features/controlLayers/konva/CanvasEntity/CanvasEntityAdapterRegionalGuidance';
|
||||
import { canvasToBlob } from 'features/controlLayers/konva/util';
|
||||
import { copyBlobToClipboard } from 'features/system/util/copyBlobToClipboard';
|
||||
import { toast } from 'features/toast/toast';
|
||||
import { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export const useCopyLayerToClipboard = () => {
|
||||
const { t } = useTranslation();
|
||||
const copyLayerToCipboard = useCallback(
|
||||
async (
|
||||
adapter:
|
||||
| CanvasEntityAdapterRasterLayer
|
||||
| CanvasEntityAdapterControlLayer
|
||||
| CanvasEntityAdapterInpaintMask
|
||||
| CanvasEntityAdapterRegionalGuidance
|
||||
| null
|
||||
) => {
|
||||
if (!adapter) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const canvas = adapter.getCanvas();
|
||||
const blob = await canvasToBlob(canvas);
|
||||
copyBlobToClipboard(blob);
|
||||
toast({
|
||||
status: 'info',
|
||||
title: t('toast.layerCopiedToClipboard'),
|
||||
});
|
||||
} catch (error) {
|
||||
toast({
|
||||
status: 'error',
|
||||
title: t('toast.problemCopyingLayer'),
|
||||
});
|
||||
}
|
||||
},
|
||||
[t]
|
||||
);
|
||||
|
||||
return copyLayerToCipboard;
|
||||
};
|
||||
@@ -299,11 +299,11 @@ export type EntityIdentifierPayload<
|
||||
U extends CanvasEntityType = CanvasEntityType,
|
||||
> = T extends void
|
||||
? {
|
||||
entityIdentifier: CanvasEntityIdentifier<U>;
|
||||
}
|
||||
entityIdentifier: CanvasEntityIdentifier<U>;
|
||||
}
|
||||
: {
|
||||
entityIdentifier: CanvasEntityIdentifier<U>;
|
||||
} & T;
|
||||
entityIdentifier: CanvasEntityIdentifier<U>;
|
||||
} & T;
|
||||
|
||||
export type EntityMovedPayload = EntityIdentifierPayload<{ position: Coordinate }>;
|
||||
export type EntityBrushLineAddedPayload = EntityIdentifierPayload<{ brushLine: CanvasBrushLineState }>;
|
||||
|
||||
Reference in New Issue
Block a user