mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
tidy(ui): organize rp layer components
This commit is contained in:
parent
642a0de3dd
commit
eb781272f7
@ -1,47 +0,0 @@
|
||||
import { Flex, Spacer } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { rgbaColorToString } from 'features/canvas/util/colorToString';
|
||||
import LayerAutoNegativeCombobox from 'features/regionalPrompts/components/LayerAutoNegativeCombobox';
|
||||
import { LayerColorPicker } from 'features/regionalPrompts/components/LayerColorPicker';
|
||||
import { LayerMenu } from 'features/regionalPrompts/components/LayerMenu';
|
||||
import { LayerVisibilityToggle } from 'features/regionalPrompts/components/LayerVisibilityToggle';
|
||||
import { RegionalPromptsNegativePrompt } from 'features/regionalPrompts/components/RegionalPromptsNegativePrompt';
|
||||
import { RegionalPromptsPositivePrompt } from 'features/regionalPrompts/components/RegionalPromptsPositivePrompt';
|
||||
import { isRegionalPromptLayer, rpLayerSelected } from 'features/regionalPrompts/store/regionalPromptsSlice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { assert } from 'tsafe';
|
||||
|
||||
type Props = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
export const LayerListItem = memo(({ id }: Props) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const selectedLayer = useAppSelector((s) => s.regionalPrompts.present.selectedLayer);
|
||||
const color = useAppSelector((s) => {
|
||||
const layer = s.regionalPrompts.present.layers.find((l) => l.id === id);
|
||||
assert(isRegionalPromptLayer(layer), `Layer ${id} not found or not an RP layer`);
|
||||
return rgbaColorToString({ ...layer.color, a: selectedLayer === id ? 1 : 0.35 });
|
||||
});
|
||||
const onClickCapture = useCallback(() => {
|
||||
// Must be capture so that the layer is selected before deleting/resetting/etc
|
||||
dispatch(rpLayerSelected(id));
|
||||
}, [dispatch, id]);
|
||||
return (
|
||||
<Flex gap={2} onClickCapture={onClickCapture} bg={color} borderRadius="base" p="1px" ps={3}>
|
||||
<Flex flexDir="column" gap={2} w="full" bg="base.850" borderRadius="base" p={2}>
|
||||
<Flex gap={2} alignItems="center">
|
||||
<LayerColorPicker id={id} />
|
||||
<LayerVisibilityToggle id={id} />
|
||||
<Spacer />
|
||||
<LayerAutoNegativeCombobox layerId={id} />
|
||||
<LayerMenu id={id} />
|
||||
</Flex>
|
||||
<RegionalPromptsPositivePrompt layerId={id} />
|
||||
<RegionalPromptsNegativePrompt layerId={id} />
|
||||
</Flex>
|
||||
</Flex>
|
||||
);
|
||||
});
|
||||
|
||||
LayerListItem.displayName = 'LayerListItem';
|
@ -35,7 +35,7 @@ const useAutoNegative = (layerId: string) => {
|
||||
return autoNegative;
|
||||
};
|
||||
|
||||
const AutoNegativeCombobox = ({ layerId }: Props) => {
|
||||
export const RPLayerAutoNegativeCombobox = memo(({ layerId }: Props) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
const autoNegative = useAutoNegative(layerId);
|
||||
@ -58,6 +58,6 @@ const AutoNegativeCombobox = ({ layerId }: Props) => {
|
||||
<Combobox value={value} options={options} onChange={onChange} isSearchable={false} sx={{ w: '5.2rem' }} />
|
||||
</FormControl>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
export default memo(AutoNegativeCombobox);
|
||||
RPLayerAutoNegativeCombobox.displayName = 'RPLayerAutoNegativeCombobox';
|
@ -13,26 +13,26 @@ import { PiEyedropperBold } from 'react-icons/pi';
|
||||
import { assert } from 'tsafe';
|
||||
|
||||
type Props = {
|
||||
id: string;
|
||||
layerId: string;
|
||||
};
|
||||
|
||||
export const LayerColorPicker = memo(({ id }: Props) => {
|
||||
export const RPLayerColorPicker = memo(({ layerId }: Props) => {
|
||||
const selectColor = useMemo(
|
||||
() =>
|
||||
createMemoizedSelector(selectRegionalPromptsSlice, (regionalPrompts) => {
|
||||
const layer = regionalPrompts.present.layers.find((l) => l.id === id);
|
||||
assert(isRegionalPromptLayer(layer), `Layer ${id} not found or not an RP layer`);
|
||||
const layer = regionalPrompts.present.layers.find((l) => l.id === layerId);
|
||||
assert(isRegionalPromptLayer(layer), `Layer ${layerId} not found or not an RP layer`);
|
||||
return layer.color;
|
||||
}),
|
||||
[id]
|
||||
[layerId]
|
||||
);
|
||||
const color = useAppSelector(selectColor);
|
||||
const dispatch = useAppDispatch();
|
||||
const onColorChange = useCallback(
|
||||
(color: RgbColor) => {
|
||||
dispatch(rpLayerColorChanged({ layerId: id, color }));
|
||||
dispatch(rpLayerColorChanged({ layerId, color }));
|
||||
},
|
||||
[dispatch, id]
|
||||
[dispatch, layerId]
|
||||
);
|
||||
return (
|
||||
<Popover isLazy>
|
||||
@ -48,4 +48,4 @@ export const LayerColorPicker = memo(({ id }: Props) => {
|
||||
);
|
||||
});
|
||||
|
||||
LayerColorPicker.displayName = 'LayerColorPicker';
|
||||
RPLayerColorPicker.displayName = 'RPLayerColorPicker';
|
@ -0,0 +1,47 @@
|
||||
import { Flex, Spacer } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { rgbaColorToString } from 'features/canvas/util/colorToString';
|
||||
import { RPLayerAutoNegativeCombobox } from 'features/regionalPrompts/components/RPLayerAutoNegativeCombobox';
|
||||
import { RPLayerColorPicker } from 'features/regionalPrompts/components/RPLayerColorPicker';
|
||||
import { RPLayerMenu } from 'features/regionalPrompts/components/RPLayerMenu';
|
||||
import { RPLayerNegativePrompt } from 'features/regionalPrompts/components/RPLayerNegativePrompt';
|
||||
import { RPLayerPositivePrompt } from 'features/regionalPrompts/components/RPLayerPositivePrompt';
|
||||
import { RPLayerVisibilityToggle } from 'features/regionalPrompts/components/RPLayerVisibilityToggle';
|
||||
import { isRegionalPromptLayer, rpLayerSelected } from 'features/regionalPrompts/store/regionalPromptsSlice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { assert } from 'tsafe';
|
||||
|
||||
type Props = {
|
||||
layerId: string;
|
||||
};
|
||||
|
||||
export const RPLayerListItem = memo(({ layerId }: Props) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const selectedLayer = useAppSelector((s) => s.regionalPrompts.present.selectedLayer);
|
||||
const color = useAppSelector((s) => {
|
||||
const layer = s.regionalPrompts.present.layers.find((l) => l.id === layerId);
|
||||
assert(isRegionalPromptLayer(layer), `Layer ${layerId} not found or not an RP layer`);
|
||||
return rgbaColorToString({ ...layer.color, a: selectedLayer === layerId ? 1 : 0.35 });
|
||||
});
|
||||
const onClickCapture = useCallback(() => {
|
||||
// Must be capture so that the layer is selected before deleting/resetting/etc
|
||||
dispatch(rpLayerSelected(layerId));
|
||||
}, [dispatch, layerId]);
|
||||
return (
|
||||
<Flex gap={2} onClickCapture={onClickCapture} bg={color} borderRadius="base" p="1px" ps={3}>
|
||||
<Flex flexDir="column" gap={2} w="full" bg="base.850" borderRadius="base" p={2}>
|
||||
<Flex gap={2} alignItems="center">
|
||||
<RPLayerColorPicker layerId={layerId} />
|
||||
<RPLayerVisibilityToggle layerId={layerId} />
|
||||
<Spacer />
|
||||
<RPLayerAutoNegativeCombobox layerId={layerId} />
|
||||
<RPLayerMenu layerId={layerId} />
|
||||
</Flex>
|
||||
<RPLayerPositivePrompt layerId={layerId} />
|
||||
<RPLayerNegativePrompt layerId={layerId} />
|
||||
</Flex>
|
||||
</Flex>
|
||||
);
|
||||
});
|
||||
|
||||
RPLayerListItem.displayName = 'RPLayerListItem';
|
@ -2,6 +2,7 @@ import { IconButton, Menu, MenuButton, MenuDivider, MenuItem, MenuList } from '@
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import {
|
||||
isRegionalPromptLayer,
|
||||
layerDeleted,
|
||||
layerMovedBackward,
|
||||
layerMovedForward,
|
||||
@ -21,16 +22,19 @@ import {
|
||||
PiDotsThreeVerticalBold,
|
||||
PiTrashSimpleBold,
|
||||
} from 'react-icons/pi';
|
||||
import { assert } from 'tsafe';
|
||||
|
||||
type Props = { id: string };
|
||||
type Props = { layerId: string };
|
||||
|
||||
export const LayerMenu = memo(({ id }: Props) => {
|
||||
export const RPLayerMenu = memo(({ layerId }: Props) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
const selectValidActions = useMemo(
|
||||
() =>
|
||||
createMemoizedSelector(selectRegionalPromptsSlice, (regionalPrompts) => {
|
||||
const layerIndex = regionalPrompts.present.layers.findIndex((l) => l.id === id);
|
||||
const layer = regionalPrompts.present.layers.find((l) => l.id === layerId);
|
||||
assert(isRegionalPromptLayer(layer), `Layer ${layerId} not found or not an RP layer`);
|
||||
const layerIndex = regionalPrompts.present.layers.findIndex((l) => l.id === layerId);
|
||||
const layerCount = regionalPrompts.present.layers.length;
|
||||
return {
|
||||
canMoveForward: layerIndex < layerCount - 1,
|
||||
@ -39,27 +43,27 @@ export const LayerMenu = memo(({ id }: Props) => {
|
||||
canMoveToBack: layerIndex > 0,
|
||||
};
|
||||
}),
|
||||
[id]
|
||||
[layerId]
|
||||
);
|
||||
const validActions = useAppSelector(selectValidActions);
|
||||
const moveForward = useCallback(() => {
|
||||
dispatch(layerMovedForward(id));
|
||||
}, [dispatch, id]);
|
||||
dispatch(layerMovedForward(layerId));
|
||||
}, [dispatch, layerId]);
|
||||
const moveToFront = useCallback(() => {
|
||||
dispatch(layerMovedToFront(id));
|
||||
}, [dispatch, id]);
|
||||
dispatch(layerMovedToFront(layerId));
|
||||
}, [dispatch, layerId]);
|
||||
const moveBackward = useCallback(() => {
|
||||
dispatch(layerMovedBackward(id));
|
||||
}, [dispatch, id]);
|
||||
dispatch(layerMovedBackward(layerId));
|
||||
}, [dispatch, layerId]);
|
||||
const moveToBack = useCallback(() => {
|
||||
dispatch(layerMovedToBack(id));
|
||||
}, [dispatch, id]);
|
||||
dispatch(layerMovedToBack(layerId));
|
||||
}, [dispatch, layerId]);
|
||||
const resetLayer = useCallback(() => {
|
||||
dispatch(rpLayerReset(id));
|
||||
}, [dispatch, id]);
|
||||
dispatch(rpLayerReset(layerId));
|
||||
}, [dispatch, layerId]);
|
||||
const deleteLayer = useCallback(() => {
|
||||
dispatch(layerDeleted(id));
|
||||
}, [dispatch, id]);
|
||||
dispatch(layerDeleted(layerId));
|
||||
}, [dispatch, layerId]);
|
||||
return (
|
||||
<Menu>
|
||||
<MenuButton as={IconButton} aria-label="Layer menu" size="sm" icon={<PiDotsThreeVerticalBold />} />
|
||||
@ -88,4 +92,4 @@ export const LayerMenu = memo(({ id }: Props) => {
|
||||
);
|
||||
});
|
||||
|
||||
LayerMenu.displayName = 'LayerMenu';
|
||||
RPLayerMenu.displayName = 'RPLayerMenu';
|
@ -15,7 +15,7 @@ type Props = {
|
||||
layerId: string;
|
||||
};
|
||||
|
||||
export const RegionalPromptsNegativePrompt = memo((props: Props) => {
|
||||
export const RPLayerNegativePrompt = memo((props: Props) => {
|
||||
const prompt = useLayerNegativePrompt(props.layerId);
|
||||
const dispatch = useAppDispatch();
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
@ -64,4 +64,4 @@ export const RegionalPromptsNegativePrompt = memo((props: Props) => {
|
||||
);
|
||||
});
|
||||
|
||||
RegionalPromptsNegativePrompt.displayName = 'RegionalPromptsPrompt';
|
||||
RPLayerNegativePrompt.displayName = 'RPLayerNegativePrompt';
|
@ -15,7 +15,7 @@ type Props = {
|
||||
layerId: string;
|
||||
};
|
||||
|
||||
export const RegionalPromptsPositivePrompt = memo((props: Props) => {
|
||||
export const RPLayerPositivePrompt = memo((props: Props) => {
|
||||
const prompt = useLayerPositivePrompt(props.layerId);
|
||||
const dispatch = useAppDispatch();
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
@ -64,4 +64,4 @@ export const RegionalPromptsPositivePrompt = memo((props: Props) => {
|
||||
);
|
||||
});
|
||||
|
||||
RegionalPromptsPositivePrompt.displayName = 'RegionalPromptsPrompt';
|
||||
RPLayerPositivePrompt.displayName = 'RPLayerPositivePrompt';
|
@ -6,15 +6,15 @@ import { memo, useCallback } from 'react';
|
||||
import { PiEyeBold, PiEyeClosedBold } from 'react-icons/pi';
|
||||
|
||||
type Props = {
|
||||
id: string;
|
||||
layerId: string;
|
||||
};
|
||||
|
||||
export const LayerVisibilityToggle = memo(({ id }: Props) => {
|
||||
export const RPLayerVisibilityToggle = memo(({ layerId }: Props) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const isVisible = useLayerIsVisible(id);
|
||||
const isVisible = useLayerIsVisible(layerId);
|
||||
const onClick = useCallback(() => {
|
||||
dispatch(rpLayerIsVisibleToggled(id));
|
||||
}, [dispatch, id]);
|
||||
dispatch(rpLayerIsVisibleToggled(layerId));
|
||||
}, [dispatch, layerId]);
|
||||
|
||||
return (
|
||||
<IconButton
|
||||
@ -27,4 +27,4 @@ export const LayerVisibilityToggle = memo(({ id }: Props) => {
|
||||
);
|
||||
});
|
||||
|
||||
LayerVisibilityToggle.displayName = 'LayerVisibilityToggle';
|
||||
RPLayerVisibilityToggle.displayName = 'RPLayerVisibilityToggle';
|
@ -5,17 +5,20 @@ import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { AddLayerButton } from 'features/regionalPrompts/components/AddLayerButton';
|
||||
import { BrushSize } from 'features/regionalPrompts/components/BrushSize';
|
||||
import { DeleteAllLayersButton } from 'features/regionalPrompts/components/DeleteAllLayersButton';
|
||||
import { LayerListItem } from 'features/regionalPrompts/components/LayerListItem';
|
||||
import { PromptLayerOpacity } from 'features/regionalPrompts/components/PromptLayerOpacity';
|
||||
import { RPLayerListItem } from 'features/regionalPrompts/components/RPLayerListItem';
|
||||
import { StageComponent } from 'features/regionalPrompts/components/StageComponent';
|
||||
import { ToolChooser } from 'features/regionalPrompts/components/ToolChooser';
|
||||
import { UndoRedoButtonGroup } from 'features/regionalPrompts/components/UndoRedoButtonGroup';
|
||||
import { selectRegionalPromptsSlice } from 'features/regionalPrompts/store/regionalPromptsSlice';
|
||||
import { isRegionalPromptLayer, selectRegionalPromptsSlice } from 'features/regionalPrompts/store/regionalPromptsSlice';
|
||||
import { getRegionalPromptLayerBlobs } from 'features/regionalPrompts/util/getLayerBlobs';
|
||||
import { memo } from 'react';
|
||||
|
||||
const selectLayerIdsReversed = createMemoizedSelector(selectRegionalPromptsSlice, (regionalPrompts) =>
|
||||
regionalPrompts.present.layers.map((l) => l.id).reverse()
|
||||
const selectRPLayerIdsReversed = createMemoizedSelector(selectRegionalPromptsSlice, (regionalPrompts) =>
|
||||
regionalPrompts.present.layers
|
||||
.filter(isRegionalPromptLayer)
|
||||
.map((l) => l.id)
|
||||
.reverse()
|
||||
);
|
||||
|
||||
const debugBlobs = () => {
|
||||
@ -23,7 +26,7 @@ const debugBlobs = () => {
|
||||
};
|
||||
|
||||
export const RegionalPromptsEditor = memo(() => {
|
||||
const layerIdsReversed = useAppSelector(selectLayerIdsReversed);
|
||||
const rpLayerIdsReversed = useAppSelector(selectRPLayerIdsReversed);
|
||||
return (
|
||||
<Flex gap={4} w="full" h="full">
|
||||
<Flex flexDir="column" gap={4} flexShrink={0}>
|
||||
@ -38,8 +41,8 @@ export const RegionalPromptsEditor = memo(() => {
|
||||
</Flex>
|
||||
<BrushSize />
|
||||
<PromptLayerOpacity />
|
||||
{layerIdsReversed.map((id) => (
|
||||
<LayerListItem key={id} id={id} />
|
||||
{rpLayerIdsReversed.map((id) => (
|
||||
<RPLayerListItem key={id} layerId={id} />
|
||||
))}
|
||||
</Flex>
|
||||
<StageComponent />
|
||||
|
Loading…
Reference in New Issue
Block a user