From 048bd18e107c68304e07a78d7cce1135bf739f52 Mon Sep 17 00:00:00 2001
From: psychedelicious <4822129+psychedelicious@users.noreply.github.com>
Date: Tue, 30 Apr 2024 11:57:16 +1000
Subject: [PATCH] feat(ui): separate ca layer opacity
---
invokeai/frontend/web/public/locales/en.json | 3 +-
.../components/CALayerOpacity.tsx | 81 +++++++++++++++++++
.../ControlAdapterLayerListItem.tsx | 2 +
.../regionalPrompts/hooks/layerStateHooks.ts | 20 ++++-
4 files changed, 104 insertions(+), 2 deletions(-)
create mode 100644 invokeai/frontend/web/src/features/regionalPrompts/components/CALayerOpacity.tsx
diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json
index d901c4be74..3a6f88e404 100644
--- a/invokeai/frontend/web/public/locales/en.json
+++ b/invokeai/frontend/web/public/locales/en.json
@@ -1536,6 +1536,7 @@
"maskedGuidance": "Masked Guidance",
"maskedGuidanceLayer": "$t(regionalPrompts.maskedGuidance) $t(unifiedCanvas.layer)",
"controlNetLayer": "$t(common.controlNet) $t(unifiedCanvas.layer)",
- "ipAdapterLayer": "$t(common.ipAdapter) $t(unifiedCanvas.layer)"
+ "ipAdapterLayer": "$t(common.ipAdapter) $t(unifiedCanvas.layer)",
+ "opacity": "Opacity"
}
}
diff --git a/invokeai/frontend/web/src/features/regionalPrompts/components/CALayerOpacity.tsx b/invokeai/frontend/web/src/features/regionalPrompts/components/CALayerOpacity.tsx
new file mode 100644
index 0000000000..9d7649be2e
--- /dev/null
+++ b/invokeai/frontend/web/src/features/regionalPrompts/components/CALayerOpacity.tsx
@@ -0,0 +1,81 @@
+import {
+ CompositeNumberInput,
+ CompositeSlider,
+ Flex,
+ FormControl,
+ FormLabel,
+ IconButton,
+ Popover,
+ PopoverArrow,
+ PopoverBody,
+ PopoverContent,
+ PopoverTrigger,
+} from '@invoke-ai/ui-library';
+import { useAppDispatch } from 'app/store/storeHooks';
+import { useLayerOpacity } from 'features/regionalPrompts/hooks/layerStateHooks';
+import { layerOpacityChanged } from 'features/regionalPrompts/store/regionalPromptsSlice';
+import { memo, useCallback } from 'react';
+import { useTranslation } from 'react-i18next';
+import { PiDropHalfFill } from 'react-icons/pi';
+
+type Props = {
+ layerId: string;
+};
+
+const marks = [0, 25, 50, 75, 100];
+const formatPct = (v: number | string) => `${v} %`;
+
+const CALayerOpacity = ({ layerId }: Props) => {
+ const { t } = useTranslation();
+ const dispatch = useAppDispatch();
+ const opacity = useLayerOpacity(layerId);
+ const onChange = useCallback(
+ (v: number) => {
+ dispatch(layerOpacityChanged({ layerId, opacity: v / 100 }));
+ },
+ [dispatch, layerId]
+ );
+ return (
+
+
+ }
+ variant="ghost"
+ />
+
+
+
+
+
+
+ {t('regionalPrompts.opacity')}
+
+
+
+
+
+
+
+ );
+};
+
+export default memo(CALayerOpacity);
diff --git a/invokeai/frontend/web/src/features/regionalPrompts/components/ControlAdapterLayerListItem.tsx b/invokeai/frontend/web/src/features/regionalPrompts/components/ControlAdapterLayerListItem.tsx
index ef94b4c75a..f9ec37e159 100644
--- a/invokeai/frontend/web/src/features/regionalPrompts/components/ControlAdapterLayerListItem.tsx
+++ b/invokeai/frontend/web/src/features/regionalPrompts/components/ControlAdapterLayerListItem.tsx
@@ -1,6 +1,7 @@
import { Flex, Spacer } from '@invoke-ai/ui-library';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
+import CALayerOpacity from 'features/regionalPrompts/components/CALayerOpacity';
import ControlAdapterLayerConfig from 'features/regionalPrompts/components/controlAdapterOverrides/ControlAdapterLayerConfig';
import { LayerTitle } from 'features/regionalPrompts/components/LayerTitle';
import { RPLayerDeleteButton } from 'features/regionalPrompts/components/RPLayerDeleteButton';
@@ -52,6 +53,7 @@ export const ControlAdapterLayerListItem = memo(({ layerId }: Props) => {
+
diff --git a/invokeai/frontend/web/src/features/regionalPrompts/hooks/layerStateHooks.ts b/invokeai/frontend/web/src/features/regionalPrompts/hooks/layerStateHooks.ts
index a8fd34d50f..dd0042431c 100644
--- a/invokeai/frontend/web/src/features/regionalPrompts/hooks/layerStateHooks.ts
+++ b/invokeai/frontend/web/src/features/regionalPrompts/hooks/layerStateHooks.ts
@@ -1,6 +1,10 @@
import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/store/storeHooks';
-import { isMaskedGuidanceLayer, selectRegionalPromptsSlice } from 'features/regionalPrompts/store/regionalPromptsSlice';
+import {
+ isControlAdapterLayer,
+ isMaskedGuidanceLayer,
+ selectRegionalPromptsSlice,
+} from 'features/regionalPrompts/store/regionalPromptsSlice';
import { useMemo } from 'react';
import { assert } from 'tsafe';
@@ -61,3 +65,17 @@ export const useLayerType = (layerId: string) => {
const type = useAppSelector(selectLayer);
return type;
};
+
+export const useLayerOpacity = (layerId: string) => {
+ const selectLayer = useMemo(
+ () =>
+ createSelector(selectRegionalPromptsSlice, (regionalPrompts) => {
+ const layer = regionalPrompts.present.layers.filter(isControlAdapterLayer).find((l) => l.id === layerId);
+ assert(layer, `Layer ${layerId} not found`);
+ return Math.round(layer.opacity * 100);
+ }),
+ [layerId]
+ );
+ const opacity = useAppSelector(selectLayer);
+ return opacity;
+};