mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): add selection mode toggle
This commit is contained in:
parent
5cf9b75d77
commit
6d10e40c9b
@ -1,5 +1,8 @@
|
||||
import { useToken } from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { contextMenusClosed } from 'features/ui/store/uiSlice';
|
||||
import { useCallback } from 'react';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
@ -61,14 +64,24 @@ const nodeTypes = {
|
||||
// TODO: can we support reactflow? if not, we could style the attribution so it matches the app
|
||||
const proOptions: ProOptions = { hideAttribution: true };
|
||||
|
||||
const selector = createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const { shouldSnapToGrid, selectionMode } = nodes;
|
||||
return {
|
||||
shouldSnapToGrid,
|
||||
selectionMode,
|
||||
};
|
||||
},
|
||||
defaultSelectorOptions
|
||||
);
|
||||
|
||||
export const Flow = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const nodes = useAppSelector((state) => state.nodes.nodes);
|
||||
const edges = useAppSelector((state) => state.nodes.edges);
|
||||
const viewport = useAppSelector((state) => state.nodes.viewport);
|
||||
const shouldSnapToGrid = useAppSelector(
|
||||
(state) => state.nodes.shouldSnapToGrid
|
||||
);
|
||||
const { shouldSnapToGrid, selectionMode } = useAppSelector(selector);
|
||||
|
||||
const isValidConnection = useIsValidConnection();
|
||||
|
||||
@ -181,6 +194,7 @@ export const Flow = () => {
|
||||
style={{ borderRadius }}
|
||||
onPaneClick={handlePaneClick}
|
||||
deleteKeyCode={DELETE_KEYS}
|
||||
selectionMode={selectionMode}
|
||||
>
|
||||
<TopLeftPanel />
|
||||
<TopCenterPanel />
|
||||
|
@ -1,6 +1,7 @@
|
||||
import {
|
||||
Divider,
|
||||
Flex,
|
||||
FormLabelProps,
|
||||
Heading,
|
||||
Modal,
|
||||
ModalBody,
|
||||
@ -13,17 +14,19 @@ import {
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import IAIIconButton from 'common/components/IAIIconButton';
|
||||
import IAISwitch from 'common/components/IAISwitch';
|
||||
import { ChangeEvent, memo, useCallback } from 'react';
|
||||
import { FaCog } from 'react-icons/fa';
|
||||
import {
|
||||
selectionModeChanged,
|
||||
shouldAnimateEdgesChanged,
|
||||
shouldColorEdgesChanged,
|
||||
shouldSnapToGridChanged,
|
||||
shouldValidateGraphChanged,
|
||||
} from 'features/nodes/store/nodesSlice';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { ChangeEvent, memo, useCallback } from 'react';
|
||||
import { FaCog } from 'react-icons/fa';
|
||||
import { SelectionMode } from 'reactflow';
|
||||
|
||||
const selector = createSelector(
|
||||
stateSelector,
|
||||
@ -33,12 +36,14 @@ const selector = createSelector(
|
||||
shouldValidateGraph,
|
||||
shouldSnapToGrid,
|
||||
shouldColorEdges,
|
||||
selectionMode,
|
||||
} = nodes;
|
||||
return {
|
||||
shouldAnimateEdges,
|
||||
shouldValidateGraph,
|
||||
shouldSnapToGrid,
|
||||
shouldColorEdges,
|
||||
selectionModeIsChecked: selectionMode === SelectionMode.Full,
|
||||
};
|
||||
},
|
||||
defaultSelectorOptions
|
||||
@ -52,6 +57,7 @@ const NodeEditorSettings = () => {
|
||||
shouldValidateGraph,
|
||||
shouldSnapToGrid,
|
||||
shouldColorEdges,
|
||||
selectionModeIsChecked,
|
||||
} = useAppSelector(selector);
|
||||
|
||||
const handleChangeShouldValidate = useCallback(
|
||||
@ -82,6 +88,13 @@ const NodeEditorSettings = () => {
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const handleChangeSelectionMode = useCallback(
|
||||
(e: ChangeEvent<HTMLInputElement>) => {
|
||||
dispatch(selectionModeChanged(e.target.checked));
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<IAIIconButton
|
||||
@ -105,6 +118,7 @@ const NodeEditorSettings = () => {
|
||||
>
|
||||
<Heading size="sm">General</Heading>
|
||||
<IAISwitch
|
||||
formLabelProps={formLabelProps}
|
||||
onChange={handleChangeShouldAnimate}
|
||||
isChecked={shouldAnimateEdges}
|
||||
label="Animated Edges"
|
||||
@ -112,6 +126,7 @@ const NodeEditorSettings = () => {
|
||||
/>
|
||||
<Divider />
|
||||
<IAISwitch
|
||||
formLabelProps={formLabelProps}
|
||||
isChecked={shouldSnapToGrid}
|
||||
onChange={handleChangeShouldSnap}
|
||||
label="Snap to Grid"
|
||||
@ -119,15 +134,24 @@ const NodeEditorSettings = () => {
|
||||
/>
|
||||
<Divider />
|
||||
<IAISwitch
|
||||
formLabelProps={formLabelProps}
|
||||
isChecked={shouldColorEdges}
|
||||
onChange={handleChangeShouldColor}
|
||||
label="Color-Code Edges"
|
||||
helperText="Color-code edges according to their connected fields"
|
||||
/>
|
||||
<IAISwitch
|
||||
formLabelProps={formLabelProps}
|
||||
isChecked={selectionModeIsChecked}
|
||||
onChange={handleChangeSelectionMode}
|
||||
label="Fully Contain Nodes to Select"
|
||||
helperText="Nodes must be fully inside the selection box to be selected"
|
||||
/>
|
||||
<Heading size="sm" pt={4}>
|
||||
Advanced
|
||||
</Heading>
|
||||
<IAISwitch
|
||||
formLabelProps={formLabelProps}
|
||||
isChecked={shouldValidateGraph}
|
||||
onChange={handleChangeShouldValidate}
|
||||
label="Validate Connections and Graph"
|
||||
@ -142,3 +166,7 @@ const NodeEditorSettings = () => {
|
||||
};
|
||||
|
||||
export default memo(NodeEditorSettings);
|
||||
|
||||
const formLabelProps: FormLabelProps = {
|
||||
fontWeight: 600,
|
||||
};
|
||||
|
@ -14,6 +14,7 @@ import {
|
||||
Node,
|
||||
NodeChange,
|
||||
OnConnectStartParams,
|
||||
SelectionMode,
|
||||
Viewport,
|
||||
} from 'reactflow';
|
||||
import { receivedOpenAPISchema } from 'services/api/thunks/schema';
|
||||
@ -103,6 +104,7 @@ export const initialNodesState: NodesState = {
|
||||
mouseOverField: null,
|
||||
nodesToCopy: [],
|
||||
edgesToCopy: [],
|
||||
selectionMode: SelectionMode.Partial,
|
||||
};
|
||||
|
||||
type FieldValueAction<T extends InputFieldValue> = PayloadAction<{
|
||||
@ -721,6 +723,11 @@ const nodesSlice = createSlice({
|
||||
addNodePopoverToggled: (state) => {
|
||||
state.isAddNodePopoverOpen = !state.isAddNodePopoverOpen;
|
||||
},
|
||||
selectionModeChanged: (state, action: PayloadAction<boolean>) => {
|
||||
state.selectionMode = action.payload
|
||||
? SelectionMode.Full
|
||||
: SelectionMode.Partial;
|
||||
},
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
builder.addCase(receivedOpenAPISchema.pending, (state) => {
|
||||
@ -832,6 +839,7 @@ export const {
|
||||
addNodePopoverOpened,
|
||||
addNodePopoverClosed,
|
||||
addNodePopoverToggled,
|
||||
selectionModeChanged,
|
||||
} = nodesSlice.actions;
|
||||
|
||||
export default nodesSlice.reducer;
|
||||
|
@ -1,4 +1,10 @@
|
||||
import { Edge, Node, OnConnectStartParams, Viewport } from 'reactflow';
|
||||
import {
|
||||
Edge,
|
||||
Node,
|
||||
OnConnectStartParams,
|
||||
SelectionMode,
|
||||
Viewport,
|
||||
} from 'reactflow';
|
||||
import {
|
||||
FieldIdentifier,
|
||||
FieldType,
|
||||
@ -32,4 +38,5 @@ export type NodesState = {
|
||||
nodesToCopy: Node<NodeData>[];
|
||||
edgesToCopy: Edge<InvocationEdgeExtra>[];
|
||||
isAddNodePopoverOpen: boolean;
|
||||
selectionMode: SelectionMode;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user