From 9465ff450b92f4df0fe3a568b8da3eb03698171e Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 21 Aug 2024 19:01:48 +1000 Subject: [PATCH] feat(ui): revise filter implementation --- .../components/CanvasEntityList.tsx | 23 +++-- .../ControlLayerControlAdapterModel.tsx | 25 ++--- .../components/ControlLayersEditor.tsx | 5 +- .../components/Filters/Filter.tsx | 85 ++++++----------- .../common/CanvasEntityMenuItemsFilter.tsx | 12 ++- .../controlLayers/konva/CanvasFilter.ts | 91 +++++++++++++------ .../controlLayers/konva/CanvasLayerAdapter.ts | 3 - .../controlLayers/konva/CanvasManager.ts | 4 + .../controlLayers/konva/CanvasStateApi.ts | 6 -- .../controlLayers/store/canvasV2Slice.ts | 6 +- 10 files changed, 134 insertions(+), 126 deletions(-) diff --git a/invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityList.tsx b/invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityList.tsx index 2b28bdc61e..3522895db4 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityList.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityList.tsx @@ -6,20 +6,23 @@ import { InpaintMaskList } from 'features/controlLayers/components/InpaintMask/I import { IPAdapterList } from 'features/controlLayers/components/IPAdapter/IPAdapterList'; import { RasterLayerEntityList } from 'features/controlLayers/components/RasterLayer/RasterLayerEntityList'; import { RegionalGuidanceEntityList } from 'features/controlLayers/components/RegionalGuidance/RegionalGuidanceEntityList'; +import { CanvasManagerProviderGate } from 'features/controlLayers/contexts/CanvasManagerProviderGate'; import { memo } from 'react'; export const CanvasEntityList = memo(() => { return ( - - - - - - - - - - + + + + + + + + + + + + ); }); diff --git a/invokeai/frontend/web/src/features/controlLayers/components/ControlLayer/ControlLayerControlAdapterModel.tsx b/invokeai/frontend/web/src/features/controlLayers/components/ControlLayer/ControlLayerControlAdapterModel.tsx index daf5cd9292..cf88a8ae2d 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/ControlLayer/ControlLayerControlAdapterModel.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/ControlLayer/ControlLayerControlAdapterModel.tsx @@ -1,8 +1,8 @@ import { Combobox, FormControl, Tooltip } from '@invoke-ai/ui-library'; import { useAppSelector } from 'app/store/storeHooks'; import { useGroupedModelCombobox } from 'common/hooks/useGroupedModelCombobox'; +import { useCanvasManager } from 'features/controlLayers/contexts/CanvasManagerProviderGate'; import { useEntityIdentifierContext } from 'features/controlLayers/contexts/EntityIdentifierContext'; -import { $filterConfig, $filteringEntity } from 'features/controlLayers/store/canvasV2Slice'; import { IMAGE_FILTERS, isFilterType } from 'features/controlLayers/store/types'; import { memo, useCallback, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; @@ -17,6 +17,7 @@ type Props = { export const ControlLayerControlAdapterModel = memo(({ modelKey, onChange: onChangeModel }: Props) => { const { t } = useTranslation(); const entityIdentifier = useEntityIdentifierContext(); + const canvasManager = useCanvasManager(); const currentBaseModel = useAppSelector((s) => s.canvasV2.params.model?.base); const [modelConfigs, { isLoading }] = useControlNetAndT2IAdapterModels(); const selectedModel = useMemo(() => modelConfigs.find((m) => m.key === modelKey), [modelConfigs, modelKey]); @@ -35,19 +36,21 @@ export const ControlLayerControlAdapterModel = memo(({ modelKey, onChange: onCha return; } - // Update the filter, preferring the model's default - if (isFilterType(modelConfig.default_settings?.preprocessor)) { - $filterConfig.set(IMAGE_FILTERS[modelConfig.default_settings.preprocessor].buildDefaults(modelConfig.base)); - } else { - $filterConfig.set(IMAGE_FILTERS.canny_image_processor.buildDefaults(modelConfig.base)); - } - // Open the filter popup by setting this entity as the filtering entity - if (!$filteringEntity.get()) { - $filteringEntity.set(entityIdentifier); + if (!canvasManager.filter.$adapter.get()) { + // Update the filter, preferring the model's default + if (isFilterType(modelConfig.default_settings?.preprocessor)) { + canvasManager.filter.$config.set( + IMAGE_FILTERS[modelConfig.default_settings.preprocessor].buildDefaults(modelConfig.base) + ); + } else { + canvasManager.filter.$config.set(IMAGE_FILTERS.canny_image_processor.buildDefaults(modelConfig.base)); + } + canvasManager.filter.initialize(entityIdentifier); + canvasManager.filter.previewFilter(); } }, - [entityIdentifier, modelKey, onChangeModel] + [canvasManager.filter, entityIdentifier, modelKey, onChangeModel] ); const getIsDisabled = useCallback( diff --git a/invokeai/frontend/web/src/features/controlLayers/components/ControlLayersEditor.tsx b/invokeai/frontend/web/src/features/controlLayers/components/ControlLayersEditor.tsx index d0036cf4bd..78439e6d1b 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/ControlLayersEditor.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/ControlLayersEditor.tsx @@ -6,6 +6,7 @@ import { ControlLayersToolbar } from 'features/controlLayers/components/ControlL import { Filter } from 'features/controlLayers/components/Filters/Filter'; import { StageComponent } from 'features/controlLayers/components/StageComponent'; import { StagingAreaToolbar } from 'features/controlLayers/components/StagingArea/StagingAreaToolbar'; +import { CanvasManagerProviderGate } from 'features/controlLayers/contexts/CanvasManagerProviderGate'; import { memo, useRef } from 'react'; export const CanvasEditor = memo(() => { @@ -33,7 +34,9 @@ export const CanvasEditor = memo(() => { - + + + diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Filters/Filter.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Filters/Filter.tsx index aaed63a823..b49e23110d 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/Filters/Filter.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/Filters/Filter.tsx @@ -2,8 +2,7 @@ import { Button, ButtonGroup, Flex, Heading } from '@invoke-ai/ui-library'; import { useStore } from '@nanostores/react'; import { FilterSettings } from 'features/controlLayers/components/Filters/FilterSettings'; import { FilterTypeSelect } from 'features/controlLayers/components/Filters/FilterTypeSelect'; -import { $canvasManager } from 'features/controlLayers/konva/CanvasManager'; -import { $filterConfig, $filteringEntity, $isProcessingFilter } from 'features/controlLayers/store/canvasV2Slice'; +import { useCanvasManager } from 'features/controlLayers/contexts/CanvasManagerProviderGate'; import { type FilterConfig, IMAGE_FILTERS } from 'features/controlLayers/store/types'; import { memo, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; @@ -11,64 +10,38 @@ import { PiCheckBold, PiShootingStarBold, PiXBold } from 'react-icons/pi'; export const Filter = memo(() => { const { t } = useTranslation(); - const filteringEntity = useStore($filteringEntity); - const filterConfig = useStore($filterConfig); - const isProcessingFilter = useStore($isProcessingFilter); + const canvasManager = useCanvasManager(); + const adapter = useStore(canvasManager.filter.$adapter); + const config = useStore(canvasManager.filter.$config); + const isProcessing = useStore(canvasManager.filter.$isProcessing); const previewFilter = useCallback(() => { - if (!filteringEntity) { - return; - } - const canvasManager = $canvasManager.get(); - if (!canvasManager) { - return; - } - const entity = canvasManager.stateApi.getEntity(filteringEntity); - if (!entity || (entity.type !== 'raster_layer' && entity.type !== 'control_layer')) { - return; - } - entity.adapter.filter.previewFilter(); - }, [filteringEntity]); + canvasManager.filter.previewFilter(); + }, [canvasManager.filter]); const applyFilter = useCallback(() => { - if (!filteringEntity) { - return; - } - const canvasManager = $canvasManager.get(); - if (!canvasManager) { - return; - } - const entity = canvasManager.stateApi.getEntity(filteringEntity); - if (!entity || (entity.type !== 'raster_layer' && entity.type !== 'control_layer')) { - return; - } - entity.adapter.filter.applyFilter(); - }, [filteringEntity]); + canvasManager.filter.applyFilter(); + }, [canvasManager.filter]); const cancelFilter = useCallback(() => { - if (!filteringEntity) { - return; - } - const canvasManager = $canvasManager.get(); - if (!canvasManager) { - return; - } - const entity = canvasManager.stateApi.getEntity(filteringEntity); - if (!entity || (entity.type !== 'raster_layer' && entity.type !== 'control_layer')) { - return; - } - entity.adapter.filter.cancelFilter(); - }, [filteringEntity]); + canvasManager.filter.cancelFilter(); + }, [canvasManager.filter]); - const onChangeFilterConfig = useCallback((filterConfig: FilterConfig) => { - $filterConfig.set(filterConfig); - }, []); + const onChangeFilterConfig = useCallback( + (filterConfig: FilterConfig) => { + canvasManager.filter.$config.set(filterConfig); + }, + [canvasManager.filter.$config] + ); - const onChangeFilterType = useCallback((filterType: FilterConfig['type']) => { - $filterConfig.set(IMAGE_FILTERS[filterType].buildDefaults()); - }, []); + const onChangeFilterType = useCallback( + (filterType: FilterConfig['type']) => { + canvasManager.filter.$config.set(IMAGE_FILTERS[filterType].buildDefaults()); + }, + [canvasManager.filter.$config] + ); - if (!filteringEntity || !filterConfig) { + if (!adapter) { return null; } @@ -88,13 +61,13 @@ export const Filter = memo(() => { {t('controlLayers.filter.filter')} - - + +