From a09aa232a9426d42ea56d461961c4e260a4ff1a1 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 23 Aug 2024 17:10:32 +1000 Subject: [PATCH] feat(ui): update entity list menu --- invokeai/frontend/web/public/locales/en.json | 1 + .../components/AddLayerButton.tsx | 57 ------------- .../components/CanvasEntityListMenu.tsx | 80 +++++++++++++++++++ .../controlLayers/store/canvasV2Slice.ts | 2 +- .../ParametersPanelTextToImage.tsx | 4 +- 5 files changed, 84 insertions(+), 60 deletions(-) delete mode 100644 invokeai/frontend/web/src/features/controlLayers/components/AddLayerButton.tsx create mode 100644 invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityListMenu.tsx diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index bace0d040e..faed7ce4b6 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -1657,6 +1657,7 @@ "autoSave": "Auto-save to Gallery", "resetCanvas": "Reset Canvas", "resetAll": "Reset All", + "deleteAll": "Delete All", "clearCaches": "Clear Caches", "recalculateRects": "Recalculate Rects", "clipToBbox": "Clip Strokes to Bbox", diff --git a/invokeai/frontend/web/src/features/controlLayers/components/AddLayerButton.tsx b/invokeai/frontend/web/src/features/controlLayers/components/AddLayerButton.tsx deleted file mode 100644 index b9d3b0fc62..0000000000 --- a/invokeai/frontend/web/src/features/controlLayers/components/AddLayerButton.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { IconButton, Menu, MenuButton, MenuItem, MenuList } from '@invoke-ai/ui-library'; -import { useAppDispatch } from 'app/store/storeHooks'; -import { useDefaultControlAdapter, useDefaultIPAdapter } from 'features/controlLayers/hooks/useLayerControlAdapter'; -import { - controlLayerAdded, - inpaintMaskAdded, - ipaAdded, - rasterLayerAdded, - rgAdded, -} from 'features/controlLayers/store/canvasV2Slice'; -import { memo, useCallback } from 'react'; -import { useTranslation } from 'react-i18next'; -import { PiPlusBold } from 'react-icons/pi'; - -export const AddLayerButton = memo(() => { - const { t } = useTranslation(); - const dispatch = useAppDispatch(); - const defaultControlAdapter = useDefaultControlAdapter(); - const defaultIPAdapter = useDefaultIPAdapter(); - const addInpaintMask = useCallback(() => { - dispatch(inpaintMaskAdded()); - }, [dispatch]); - const addRegionalGuidance = useCallback(() => { - dispatch(rgAdded()); - }, [dispatch]); - const addRasterLayer = useCallback(() => { - dispatch(rasterLayerAdded({ isSelected: true })); - }, [dispatch]); - const addControlLayer = useCallback(() => { - dispatch(controlLayerAdded({ isSelected: true, overrides: { controlAdapter: defaultControlAdapter } })); - }, [defaultControlAdapter, dispatch]); - const addIPAdapter = useCallback(() => { - dispatch(ipaAdded({ ipAdapter: defaultIPAdapter })); - }, [defaultIPAdapter, dispatch]); - - return ( - - } - variant="link" - data-testid="control-layers-add-layer-menu-button" - alignSelf="stretch" - /> - - {t('controlLayers.inpaintMask', { count: 1 })} - {t('controlLayers.regionalGuidance', { count: 1 })} - {t('controlLayers.rasterLayer', { count: 1 })} - {t('controlLayers.controlLayer', { count: 1 })} - {t('controlLayers.ipAdapter', { count: 1 })} - - - ); -}); - -AddLayerButton.displayName = 'AddLayerButton'; diff --git a/invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityListMenu.tsx b/invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityListMenu.tsx new file mode 100644 index 0000000000..1ef30d92c3 --- /dev/null +++ b/invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityListMenu.tsx @@ -0,0 +1,80 @@ +import { IconButton, Menu, MenuButton, MenuDivider, MenuItem, MenuList } from '@invoke-ai/ui-library'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { useDefaultControlAdapter, useDefaultIPAdapter } from 'features/controlLayers/hooks/useLayerControlAdapter'; +import { + allEntitiesDeleted, + controlLayerAdded, + inpaintMaskAdded, + ipaAdded, + rasterLayerAdded, + rgAdded, +} from 'features/controlLayers/store/canvasV2Slice'; +import { selectEntityCount } from 'features/controlLayers/store/selectors'; +import { memo, useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; +import { PiDotsThreeOutlineFill, PiPlusBold, PiTrashSimpleBold } from 'react-icons/pi'; + +export const CanvasEntityListMenu = memo(() => { + const { t } = useTranslation(); + const dispatch = useAppDispatch(); + const hasEntities = useAppSelector((s) => { + const count = selectEntityCount(s); + return count > 0; + }); + const defaultControlAdapter = useDefaultControlAdapter(); + const defaultIPAdapter = useDefaultIPAdapter(); + const addInpaintMask = useCallback(() => { + dispatch(inpaintMaskAdded()); + }, [dispatch]); + const addRegionalGuidance = useCallback(() => { + dispatch(rgAdded()); + }, [dispatch]); + const addRasterLayer = useCallback(() => { + dispatch(rasterLayerAdded({ isSelected: true })); + }, [dispatch]); + const addControlLayer = useCallback(() => { + dispatch(controlLayerAdded({ isSelected: true, overrides: { controlAdapter: defaultControlAdapter } })); + }, [defaultControlAdapter, dispatch]); + const addIPAdapter = useCallback(() => { + dispatch(ipaAdded({ ipAdapter: defaultIPAdapter })); + }, [defaultIPAdapter, dispatch]); + const deleteAll = useCallback(() => { + dispatch(allEntitiesDeleted()); + }, [dispatch]); + + return ( + + } + variant="link" + data-testid="control-layers-add-layer-menu-button" + alignSelf="stretch" + /> + + } onClick={addInpaintMask}> + {t('controlLayers.inpaintMask', { count: 1 })} + + } onClick={addRegionalGuidance}> + {t('controlLayers.regionalGuidance', { count: 1 })} + + } onClick={addRasterLayer}> + {t('controlLayers.rasterLayer', { count: 1 })} + + } onClick={addControlLayer}> + {t('controlLayers.controlLayer', { count: 1 })} + + } onClick={addIPAdapter}> + {t('controlLayers.ipAdapter', { count: 1 })} + + + } color="error.300" isDisabled={!hasEntities}> + {t('controlLayers.deleteAll', { count: 1 })} + + + + ); +}); + +CanvasEntityListMenu.displayName = 'CanvasEntityListMenu'; diff --git a/invokeai/frontend/web/src/features/controlLayers/store/canvasV2Slice.ts b/invokeai/frontend/web/src/features/controlLayers/store/canvasV2Slice.ts index 3fe07ff5bc..3b32084905 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/canvasV2Slice.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/canvasV2Slice.ts @@ -439,7 +439,6 @@ export const { invertScrollChanged, toolChanged, toolBufferChanged, - allEntitiesDeleted, clipToBboxChanged, canvasReset, settingsDynamicGridToggled, @@ -460,6 +459,7 @@ export const { entityArrangedBackwardOne, entityArrangedToBack, entityOpacityChanged, + allEntitiesDeleted, allEntitiesOfTypeIsHiddenToggled, // bbox bboxChanged, diff --git a/invokeai/frontend/web/src/features/ui/components/ParametersPanels/ParametersPanelTextToImage.tsx b/invokeai/frontend/web/src/features/ui/components/ParametersPanels/ParametersPanelTextToImage.tsx index 3faa520471..1b39f40227 100644 --- a/invokeai/frontend/web/src/features/ui/components/ParametersPanels/ParametersPanelTextToImage.tsx +++ b/invokeai/frontend/web/src/features/ui/components/ParametersPanels/ParametersPanelTextToImage.tsx @@ -3,7 +3,7 @@ import { Box, Flex, Spacer, Tab, TabList, TabPanel, TabPanels, Tabs } from '@inv import { useStore } from '@nanostores/react'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { overlayScrollbarsParams } from 'common/components/OverlayScrollbars/constants'; -import { AddLayerButton } from 'features/controlLayers/components/AddLayerButton'; +import { CanvasEntityListMenu } from 'features/controlLayers/components/CanvasEntityListMenu'; import { CanvasPanelContent } from 'features/controlLayers/components/CanvasPanelContent'; import { $isPreviewVisible } from 'features/controlLayers/store/canvasV2Slice'; import { selectEntityCount } from 'features/controlLayers/store/selectors'; @@ -102,7 +102,7 @@ const ParametersPanelTextToImage = () => { {controlLayersTitle} - +