From ace3955760ae6372dbb4d86ce8c9de9f22ae759e Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 30 Apr 2024 12:29:35 +1000 Subject: [PATCH] fix(ui): tool preview/cursor when non-interactable layer selected --- .../regionalPrompts/components/StageComponent.tsx | 9 +++++++++ .../regionalPrompts/components/ToolChooser.tsx | 15 +++++++++++++-- .../features/regionalPrompts/util/renderers.ts | 4 ++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/invokeai/frontend/web/src/features/regionalPrompts/components/StageComponent.tsx b/invokeai/frontend/web/src/features/regionalPrompts/components/StageComponent.tsx index 721ddf9d8e..83f589a392 100644 --- a/invokeai/frontend/web/src/features/regionalPrompts/components/StageComponent.tsx +++ b/invokeai/frontend/web/src/features/regionalPrompts/components/StageComponent.tsx @@ -1,5 +1,6 @@ import { Flex } from '@invoke-ai/ui-library'; import { useStore } from '@nanostores/react'; +import { createSelector } from '@reduxjs/toolkit'; import { logger } from 'app/logging/logger'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; @@ -33,6 +34,11 @@ const selectSelectedLayerColor = createMemoizedSelector(selectRegionalPromptsSli return layer?.previewColor ?? null; }); +const selectSelectedLayerType = createSelector(selectRegionalPromptsSlice, (regionalPrompts) => { + const selectedLayer = regionalPrompts.present.layers.find((l) => l.id === regionalPrompts.present.selectedLayerId); + return selectedLayer?.type ?? null; +}); + const useStageRenderer = ( stage: Konva.Stage, container: HTMLDivElement | null, @@ -47,6 +53,7 @@ const useStageRenderer = ( const lastMouseDownPos = useStore($lastMouseDownPos); const isMouseOver = useStore($isMouseOver); const selectedLayerIdColor = useAppSelector(selectSelectedLayerColor); + const selectedLayerType = useAppSelector(selectSelectedLayerType); const layerIds = useMemo(() => state.layers.map((l) => l.id), [state.layers]); const renderers = useMemo(() => (asPreview ? debouncedRenderers : normalRenderers), [asPreview]); const dpr = useDevicePixelRatio({ round: false }); @@ -135,6 +142,7 @@ const useStageRenderer = ( stage, tool, selectedLayerIdColor, + selectedLayerType, state.globalMaskLayerOpacity, cursorPosition, lastMouseDownPos, @@ -146,6 +154,7 @@ const useStageRenderer = ( stage, tool, selectedLayerIdColor, + selectedLayerType, state.globalMaskLayerOpacity, cursorPosition, lastMouseDownPos, diff --git a/invokeai/frontend/web/src/features/regionalPrompts/components/ToolChooser.tsx b/invokeai/frontend/web/src/features/regionalPrompts/components/ToolChooser.tsx index 80ed271289..a3b556a7e5 100644 --- a/invokeai/frontend/web/src/features/regionalPrompts/components/ToolChooser.tsx +++ b/invokeai/frontend/web/src/features/regionalPrompts/components/ToolChooser.tsx @@ -1,16 +1,27 @@ import { ButtonGroup, IconButton } from '@invoke-ai/ui-library'; import { useStore } from '@nanostores/react'; +import { createSelector } from '@reduxjs/toolkit'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import { $tool, selectedLayerDeleted, selectedLayerReset } from 'features/regionalPrompts/store/regionalPromptsSlice'; +import { + $tool, + selectedLayerDeleted, + selectedLayerReset, + selectRegionalPromptsSlice, +} from 'features/regionalPrompts/store/regionalPromptsSlice'; import { useCallback } from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; import { useTranslation } from 'react-i18next'; import { PiArrowsOutCardinalBold, PiEraserBold, PiPaintBrushBold, PiRectangleBold } from 'react-icons/pi'; +const selectIsDisabled = createSelector(selectRegionalPromptsSlice, (regionalPrompts) => { + const selectedLayer = regionalPrompts.present.layers.find((l) => l.id === regionalPrompts.present.selectedLayerId); + return selectedLayer?.type !== 'masked_guidance_layer'; +}); + export const ToolChooser: React.FC = () => { const { t } = useTranslation(); const dispatch = useAppDispatch(); - const isDisabled = useAppSelector((s) => s.regionalPrompts.present.layers.length === 0); + const isDisabled = useAppSelector(selectIsDisabled); const tool = useStore($tool); const setToolToBrush = useCallback(() => { diff --git a/invokeai/frontend/web/src/features/regionalPrompts/util/renderers.ts b/invokeai/frontend/web/src/features/regionalPrompts/util/renderers.ts index 944d996bff..2e437728b5 100644 --- a/invokeai/frontend/web/src/features/regionalPrompts/util/renderers.ts +++ b/invokeai/frontend/web/src/features/regionalPrompts/util/renderers.ts @@ -133,6 +133,7 @@ const renderToolPreview = ( stage: Konva.Stage, tool: Tool, color: RgbColor | null, + selectedLayerType: Layer['type'] | null, globalMaskLayerOpacity: number, cursorPos: Vector2d | null, lastMouseDownPos: Vector2d | null, @@ -144,6 +145,9 @@ const renderToolPreview = ( if (layerCount === 0) { // We have no layers, so we should not render any tool stage.container().style.cursor = 'default'; + } else if (selectedLayerType !== 'masked_guidance_layer') { + // Non-mask-guidance layers don't have tools + stage.container().style.cursor = 'not-allowed'; } else if (tool === 'move') { // Move tool gets a pointer stage.container().style.cursor = 'default';