mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): split out tool state from canvas rendering state
This commit is contained in:
parent
1303e18e93
commit
3af6d79852
@ -8,6 +8,7 @@ import { deepClone } from 'common/util/deepClone';
|
|||||||
import { changeBoardModalSlice } from 'features/changeBoardModal/store/slice';
|
import { changeBoardModalSlice } from 'features/changeBoardModal/store/slice';
|
||||||
import { canvasV2PersistConfig, canvasV2Slice } from 'features/controlLayers/store/canvasV2Slice';
|
import { canvasV2PersistConfig, canvasV2Slice } from 'features/controlLayers/store/canvasV2Slice';
|
||||||
import { paramsPersistConfig, paramsSlice } from 'features/controlLayers/store/paramsSlice';
|
import { paramsPersistConfig, paramsSlice } from 'features/controlLayers/store/paramsSlice';
|
||||||
|
import { toolPersistConfig, toolSlice } from 'features/controlLayers/store/toolSlice';
|
||||||
import { deleteImageModalSlice } from 'features/deleteImageModal/store/slice';
|
import { deleteImageModalSlice } from 'features/deleteImageModal/store/slice';
|
||||||
import { dynamicPromptsPersistConfig, dynamicPromptsSlice } from 'features/dynamicPrompts/store/dynamicPromptsSlice';
|
import { dynamicPromptsPersistConfig, dynamicPromptsSlice } from 'features/dynamicPrompts/store/dynamicPromptsSlice';
|
||||||
import { galleryPersistConfig, gallerySlice } from 'features/gallery/store/gallerySlice';
|
import { galleryPersistConfig, gallerySlice } from 'features/gallery/store/gallerySlice';
|
||||||
@ -59,6 +60,7 @@ const allReducers = {
|
|||||||
[upscaleSlice.name]: upscaleSlice.reducer,
|
[upscaleSlice.name]: upscaleSlice.reducer,
|
||||||
[stylePresetSlice.name]: stylePresetSlice.reducer,
|
[stylePresetSlice.name]: stylePresetSlice.reducer,
|
||||||
[paramsSlice.name]: paramsSlice.reducer,
|
[paramsSlice.name]: paramsSlice.reducer,
|
||||||
|
[toolSlice.name]: toolSlice.reducer,
|
||||||
};
|
};
|
||||||
|
|
||||||
const rootReducer = combineReducers(allReducers);
|
const rootReducer = combineReducers(allReducers);
|
||||||
@ -101,6 +103,7 @@ const persistConfigs: { [key in keyof typeof allReducers]?: PersistConfig } = {
|
|||||||
[upscalePersistConfig.name]: upscalePersistConfig,
|
[upscalePersistConfig.name]: upscalePersistConfig,
|
||||||
[stylePresetPersistConfig.name]: stylePresetPersistConfig,
|
[stylePresetPersistConfig.name]: stylePresetPersistConfig,
|
||||||
[paramsPersistConfig.name]: paramsPersistConfig,
|
[paramsPersistConfig.name]: paramsPersistConfig,
|
||||||
|
[toolPersistConfig.name]: toolPersistConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
const unserialize: UnserializeFunction = (data, key) => {
|
const unserialize: UnserializeFunction = (data, key) => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Checkbox, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
import { Checkbox, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { invertScrollChanged } from 'features/controlLayers/store/canvasV2Slice';
|
import { invertScrollChanged } from 'features/controlLayers/store/toolSlice';
|
||||||
import type { ChangeEvent } from 'react';
|
import type { ChangeEvent } from 'react';
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@ -8,7 +8,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
export const CanvasSettingsInvertScrollCheckbox = memo(() => {
|
export const CanvasSettingsInvertScrollCheckbox = memo(() => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const invertScroll = useAppSelector((s) => s.canvasV2.tool.invertScroll);
|
const invertScroll = useAppSelector((s) => s.tool.invertScroll);
|
||||||
const onChange = useCallback(
|
const onChange = useCallback(
|
||||||
(e: ChangeEvent<HTMLInputElement>) => dispatch(invertScrollChanged(e.target.checked)),
|
(e: ChangeEvent<HTMLInputElement>) => dispatch(invertScrollChanged(e.target.checked)),
|
||||||
[dispatch]
|
[dispatch]
|
||||||
|
@ -10,7 +10,7 @@ import {
|
|||||||
PopoverTrigger,
|
PopoverTrigger,
|
||||||
} from '@invoke-ai/ui-library';
|
} from '@invoke-ai/ui-library';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { brushWidthChanged } from 'features/controlLayers/store/canvasV2Slice';
|
import { brushWidthChanged } from 'features/controlLayers/store/toolSlice';
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ const formatPx = (v: number | string) => `${v} px`;
|
|||||||
export const ToolBrushWidth = memo(() => {
|
export const ToolBrushWidth = memo(() => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const width = useAppSelector((s) => s.canvasV2.tool.brush.width);
|
const width = useAppSelector((s) => s.tool.brush.width);
|
||||||
const onChange = useCallback(
|
const onChange = useCallback(
|
||||||
(v: number) => {
|
(v: number) => {
|
||||||
dispatch(brushWidthChanged(Math.round(v)));
|
dispatch(brushWidthChanged(Math.round(v)));
|
||||||
|
@ -10,7 +10,7 @@ import {
|
|||||||
PopoverTrigger,
|
PopoverTrigger,
|
||||||
} from '@invoke-ai/ui-library';
|
} from '@invoke-ai/ui-library';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { eraserWidthChanged } from 'features/controlLayers/store/canvasV2Slice';
|
import { eraserWidthChanged } from 'features/controlLayers/store/toolSlice';
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ const formatPx = (v: number | string) => `${v} px`;
|
|||||||
export const ToolEraserWidth = memo(() => {
|
export const ToolEraserWidth = memo(() => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const width = useAppSelector((s) => s.canvasV2.tool.eraser.width);
|
const width = useAppSelector((s) => s.tool.eraser.width);
|
||||||
const onChange = useCallback(
|
const onChange = useCallback(
|
||||||
(v: number) => {
|
(v: number) => {
|
||||||
dispatch(eraserWidthChanged(Math.round(v)));
|
dispatch(eraserWidthChanged(Math.round(v)));
|
||||||
|
@ -2,14 +2,14 @@ import { Flex, Popover, PopoverBody, PopoverContent, PopoverTrigger } from '@inv
|
|||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAIColorPicker from 'common/components/IAIColorPicker';
|
import IAIColorPicker from 'common/components/IAIColorPicker';
|
||||||
import { rgbaColorToString } from 'common/util/colorCodeTransformers';
|
import { rgbaColorToString } from 'common/util/colorCodeTransformers';
|
||||||
import { fillChanged } from 'features/controlLayers/store/canvasV2Slice';
|
import { fillChanged } from 'features/controlLayers/store/toolSlice';
|
||||||
import type { RgbaColor } from 'features/controlLayers/store/types';
|
import type { RgbaColor } from 'features/controlLayers/store/types';
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
export const ToolFillColorPicker = memo(() => {
|
export const ToolFillColorPicker = memo(() => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const fill = useAppSelector((s) => s.canvasV2.tool.fill);
|
const fill = useAppSelector((s) => s.tool.fill);
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const onChange = useCallback(
|
const onChange = useCallback(
|
||||||
(color: RgbaColor) => {
|
(color: RgbaColor) => {
|
||||||
|
@ -11,7 +11,6 @@ import type {
|
|||||||
CanvasEntityIdentifier,
|
CanvasEntityIdentifier,
|
||||||
CanvasEraserLineState,
|
CanvasEraserLineState,
|
||||||
CanvasRasterLayerState,
|
CanvasRasterLayerState,
|
||||||
CanvasV2State,
|
|
||||||
Coordinate,
|
Coordinate,
|
||||||
Rect,
|
Rect,
|
||||||
} from 'features/controlLayers/store/types';
|
} from 'features/controlLayers/store/types';
|
||||||
@ -83,11 +82,7 @@ export class CanvasLayerAdapter extends CanvasModuleBase {
|
|||||||
this.konva.layer.destroy();
|
this.konva.layer.destroy();
|
||||||
};
|
};
|
||||||
|
|
||||||
update = async (arg?: {
|
update = async (arg?: { state: CanvasLayerAdapter['state'] }) => {
|
||||||
state: CanvasLayerAdapter['state'];
|
|
||||||
toolState: CanvasV2State['tool'];
|
|
||||||
isSelected: boolean;
|
|
||||||
}) => {
|
|
||||||
const state = get(arg, 'state', this.state);
|
const state = get(arg, 'state', this.state);
|
||||||
|
|
||||||
if (!this.isFirstRender && state === this.state) {
|
if (!this.isFirstRender && state === this.state) {
|
||||||
|
@ -112,7 +112,7 @@ export class CanvasManager extends CanvasModuleBase {
|
|||||||
// These atoms require the canvas manager to be set up before we can provide their initial values
|
// These atoms require the canvas manager to be set up before we can provide their initial values
|
||||||
this.stateApi.$transformingEntity.set(null);
|
this.stateApi.$transformingEntity.set(null);
|
||||||
this.stateApi.$toolState.set(this.stateApi.getToolState());
|
this.stateApi.$toolState.set(this.stateApi.getToolState());
|
||||||
this.stateApi.$selectedEntityIdentifier.set(this.stateApi.getState().selectedEntityIdentifier);
|
this.stateApi.$selectedEntityIdentifier.set(this.stateApi.getCanvasState().selectedEntityIdentifier);
|
||||||
this.stateApi.$currentFill.set(this.stateApi.getCurrentFill());
|
this.stateApi.$currentFill.set(this.stateApi.getCurrentFill());
|
||||||
this.stateApi.$selectedEntity.set(this.stateApi.getSelectedEntity());
|
this.stateApi.$selectedEntity.set(this.stateApi.getSelectedEntity());
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@ import type {
|
|||||||
CanvasEraserLineState,
|
CanvasEraserLineState,
|
||||||
CanvasInpaintMaskState,
|
CanvasInpaintMaskState,
|
||||||
CanvasRegionalGuidanceState,
|
CanvasRegionalGuidanceState,
|
||||||
CanvasV2State,
|
|
||||||
Coordinate,
|
Coordinate,
|
||||||
Rect,
|
Rect,
|
||||||
} from 'features/controlLayers/store/types';
|
} from 'features/controlLayers/store/types';
|
||||||
@ -83,11 +82,7 @@ export class CanvasMaskAdapter extends CanvasModuleBase {
|
|||||||
this.konva.layer.destroy();
|
this.konva.layer.destroy();
|
||||||
};
|
};
|
||||||
|
|
||||||
update = async (arg?: {
|
update = async (arg?: { state: CanvasMaskAdapter['state'] }) => {
|
||||||
state: CanvasMaskAdapter['state'];
|
|
||||||
toolState: CanvasV2State['tool'];
|
|
||||||
isSelected: boolean;
|
|
||||||
}) => {
|
|
||||||
const state = get(arg, 'state', this.state);
|
const state = get(arg, 'state', this.state);
|
||||||
|
|
||||||
if (!this.isFirstRender && state === this.state && state.fill === this.state.fill) {
|
if (!this.isFirstRender && state === this.state && state.fill === this.state.fill) {
|
||||||
|
@ -28,7 +28,7 @@ export class CanvasRenderingModule extends CanvasModuleBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render = async () => {
|
render = async () => {
|
||||||
const state = this.manager.stateApi.getState();
|
const state = this.manager.stateApi.getCanvasState();
|
||||||
|
|
||||||
if (!this.state) {
|
if (!this.state) {
|
||||||
this.log.trace('First render');
|
this.log.trace('First render');
|
||||||
@ -51,7 +51,7 @@ export class CanvasRenderingModule extends CanvasModuleBase {
|
|||||||
await this.renderStagingArea(state, prevState);
|
await this.renderStagingArea(state, prevState);
|
||||||
this.arrangeEntities(state, prevState);
|
this.arrangeEntities(state, prevState);
|
||||||
|
|
||||||
this.manager.stateApi.$toolState.set(state.tool);
|
this.manager.stateApi.$toolState.set(this.manager.stateApi.getToolState());
|
||||||
this.manager.stateApi.$selectedEntityIdentifier.set(state.selectedEntityIdentifier);
|
this.manager.stateApi.$selectedEntityIdentifier.set(state.selectedEntityIdentifier);
|
||||||
this.manager.stateApi.$selectedEntity.set(this.manager.stateApi.getSelectedEntity());
|
this.manager.stateApi.$selectedEntity.set(this.manager.stateApi.getSelectedEntity());
|
||||||
this.manager.stateApi.$currentFill.set(this.manager.stateApi.getCurrentFill());
|
this.manager.stateApi.$currentFill.set(this.manager.stateApi.getCurrentFill());
|
||||||
@ -96,11 +96,7 @@ export class CanvasRenderingModule extends CanvasModuleBase {
|
|||||||
adapterMap.set(adapter.id, adapter);
|
adapterMap.set(adapter.id, adapter);
|
||||||
this.manager.stage.addLayer(adapter.konva.layer);
|
this.manager.stage.addLayer(adapter.konva.layer);
|
||||||
}
|
}
|
||||||
await adapter.update({
|
await adapter.update({ state: entityState });
|
||||||
state: entityState,
|
|
||||||
toolState: state.tool,
|
|
||||||
isSelected: state.selectedEntityIdentifier?.id === entityState.id,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -129,11 +125,7 @@ export class CanvasRenderingModule extends CanvasModuleBase {
|
|||||||
adapterMap.set(adapter.id, adapter);
|
adapterMap.set(adapter.id, adapter);
|
||||||
this.manager.stage.addLayer(adapter.konva.layer);
|
this.manager.stage.addLayer(adapter.konva.layer);
|
||||||
}
|
}
|
||||||
await adapter.update({
|
await adapter.update({ state: entityState });
|
||||||
state: entityState,
|
|
||||||
toolState: state.tool,
|
|
||||||
isSelected: state.selectedEntityIdentifier?.id === entityState.id,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -167,11 +159,7 @@ export class CanvasRenderingModule extends CanvasModuleBase {
|
|||||||
adapterMap.set(adapter.id, adapter);
|
adapterMap.set(adapter.id, adapter);
|
||||||
this.manager.stage.addLayer(adapter.konva.layer);
|
this.manager.stage.addLayer(adapter.konva.layer);
|
||||||
}
|
}
|
||||||
await adapter.update({
|
await adapter.update({ state: entityState });
|
||||||
state: entityState,
|
|
||||||
toolState: state.tool,
|
|
||||||
isSelected: state.selectedEntityIdentifier?.id === entityState.id,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -205,11 +193,7 @@ export class CanvasRenderingModule extends CanvasModuleBase {
|
|||||||
adapterMap.set(adapter.id, adapter);
|
adapterMap.set(adapter.id, adapter);
|
||||||
this.manager.stage.addLayer(adapter.konva.layer);
|
this.manager.stage.addLayer(adapter.konva.layer);
|
||||||
}
|
}
|
||||||
await adapter.update({
|
await adapter.update({ state: entityState });
|
||||||
state: entityState,
|
|
||||||
toolState: state.tool,
|
|
||||||
isSelected: state.selectedEntityIdentifier?.id === entityState.id,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -7,7 +7,6 @@ import { CanvasModuleBase } from 'features/controlLayers/konva/CanvasModuleBase'
|
|||||||
import { getPrefixedId } from 'features/controlLayers/konva/util';
|
import { getPrefixedId } from 'features/controlLayers/konva/util';
|
||||||
import {
|
import {
|
||||||
bboxChanged,
|
bboxChanged,
|
||||||
brushWidthChanged,
|
|
||||||
entityBrushLineAdded,
|
entityBrushLineAdded,
|
||||||
entityEraserLineAdded,
|
entityEraserLineAdded,
|
||||||
entityMoved,
|
entityMoved,
|
||||||
@ -15,17 +14,20 @@ import {
|
|||||||
entityRectAdded,
|
entityRectAdded,
|
||||||
entityReset,
|
entityReset,
|
||||||
entitySelected,
|
entitySelected,
|
||||||
eraserWidthChanged,
|
|
||||||
fillChanged,
|
|
||||||
} from 'features/controlLayers/store/canvasV2Slice';
|
} from 'features/controlLayers/store/canvasV2Slice';
|
||||||
import { selectAllRenderableEntities } from 'features/controlLayers/store/selectors';
|
import { selectAllRenderableEntities } from 'features/controlLayers/store/selectors';
|
||||||
|
import {
|
||||||
|
brushWidthChanged,
|
||||||
|
eraserWidthChanged,
|
||||||
|
fillChanged,
|
||||||
|
type ToolState,
|
||||||
|
} from 'features/controlLayers/store/toolSlice';
|
||||||
import type {
|
import type {
|
||||||
CanvasControlLayerState,
|
CanvasControlLayerState,
|
||||||
CanvasEntityIdentifier,
|
CanvasEntityIdentifier,
|
||||||
CanvasInpaintMaskState,
|
CanvasInpaintMaskState,
|
||||||
CanvasRasterLayerState,
|
CanvasRasterLayerState,
|
||||||
CanvasRegionalGuidanceState,
|
CanvasRegionalGuidanceState,
|
||||||
CanvasV2State,
|
|
||||||
Coordinate,
|
Coordinate,
|
||||||
EntityBrushLineAddedPayload,
|
EntityBrushLineAddedPayload,
|
||||||
EntityEraserLineAddedPayload,
|
EntityEraserLineAddedPayload,
|
||||||
@ -97,7 +99,7 @@ export class CanvasStateApiModule extends CanvasModuleBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reminder - use arrow functions to avoid binding issues
|
// Reminder - use arrow functions to avoid binding issues
|
||||||
getState = () => {
|
getCanvasState = () => {
|
||||||
return this.store.getState().canvasV2;
|
return this.store.getState().canvasV2;
|
||||||
};
|
};
|
||||||
resetEntity = (arg: EntityIdentifierPayload) => {
|
resetEntity = (arg: EntityIdentifierPayload) => {
|
||||||
@ -141,36 +143,36 @@ export class CanvasStateApiModule extends CanvasModuleBase {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
getBbox = () => {
|
getBbox = () => {
|
||||||
return this.getState().bbox;
|
return this.getCanvasState().bbox;
|
||||||
};
|
};
|
||||||
|
|
||||||
getToolState = () => {
|
getToolState = () => {
|
||||||
return this.getState().tool;
|
return this.store.getState().tool;
|
||||||
};
|
};
|
||||||
getSettings = () => {
|
getSettings = () => {
|
||||||
return this.getState().settings;
|
return this.getCanvasState().settings;
|
||||||
};
|
};
|
||||||
getRegionsState = () => {
|
getRegionsState = () => {
|
||||||
return this.getState().regions;
|
return this.getCanvasState().regions;
|
||||||
};
|
};
|
||||||
getRasterLayersState = () => {
|
getRasterLayersState = () => {
|
||||||
return this.getState().rasterLayers;
|
return this.getCanvasState().rasterLayers;
|
||||||
};
|
};
|
||||||
getControlLayersState = () => {
|
getControlLayersState = () => {
|
||||||
return this.getState().controlLayers;
|
return this.getCanvasState().controlLayers;
|
||||||
};
|
};
|
||||||
getInpaintMasksState = () => {
|
getInpaintMasksState = () => {
|
||||||
return this.getState().inpaintMasks;
|
return this.getCanvasState().inpaintMasks;
|
||||||
};
|
};
|
||||||
getSession = () => {
|
getSession = () => {
|
||||||
return this.getState().session;
|
return this.getCanvasState().session;
|
||||||
};
|
};
|
||||||
getIsSelected = (id: string) => {
|
getIsSelected = (id: string) => {
|
||||||
return this.getState().selectedEntityIdentifier?.id === id;
|
return this.getCanvasState().selectedEntityIdentifier?.id === id;
|
||||||
};
|
};
|
||||||
|
|
||||||
getEntity(identifier: CanvasEntityIdentifier): EntityStateAndAdapter | null {
|
getEntity(identifier: CanvasEntityIdentifier): EntityStateAndAdapter | null {
|
||||||
const state = this.getState();
|
const state = this.getCanvasState();
|
||||||
|
|
||||||
let entityState: EntityStateAndAdapter['state'] | null = null;
|
let entityState: EntityStateAndAdapter['state'] | null = null;
|
||||||
let entityAdapter: EntityStateAndAdapter['adapter'] | null = null;
|
let entityAdapter: EntityStateAndAdapter['adapter'] | null = null;
|
||||||
@ -202,7 +204,7 @@ export class CanvasStateApiModule extends CanvasModuleBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getRenderedEntityCount = () => {
|
getRenderedEntityCount = () => {
|
||||||
const renderableEntities = selectAllRenderableEntities(this.getState());
|
const renderableEntities = selectAllRenderableEntities(this.getCanvasState());
|
||||||
let count = 0;
|
let count = 0;
|
||||||
for (const entity of renderableEntities) {
|
for (const entity of renderableEntities) {
|
||||||
if (entity.isEnabled) {
|
if (entity.isEnabled) {
|
||||||
@ -213,7 +215,7 @@ export class CanvasStateApiModule extends CanvasModuleBase {
|
|||||||
};
|
};
|
||||||
|
|
||||||
getSelectedEntity = () => {
|
getSelectedEntity = () => {
|
||||||
const state = this.getState();
|
const state = this.getCanvasState();
|
||||||
if (state.selectedEntityIdentifier) {
|
if (state.selectedEntityIdentifier) {
|
||||||
return this.getEntity(state.selectedEntityIdentifier);
|
return this.getEntity(state.selectedEntityIdentifier);
|
||||||
}
|
}
|
||||||
@ -221,8 +223,7 @@ export class CanvasStateApiModule extends CanvasModuleBase {
|
|||||||
};
|
};
|
||||||
|
|
||||||
getCurrentFill = () => {
|
getCurrentFill = () => {
|
||||||
const state = this.getState();
|
let currentFill: RgbaColor = this.getToolState().fill;
|
||||||
let currentFill: RgbaColor = state.tool.fill;
|
|
||||||
const selectedEntity = this.getSelectedEntity();
|
const selectedEntity = this.getSelectedEntity();
|
||||||
if (selectedEntity) {
|
if (selectedEntity) {
|
||||||
// These two entity types use a compositing rect for opacity. Their fill is always a solid color.
|
// These two entity types use a compositing rect for opacity. Their fill is always a solid color.
|
||||||
@ -239,15 +240,14 @@ export class CanvasStateApiModule extends CanvasModuleBase {
|
|||||||
// The brush should use the mask opacity for these enktity types
|
// The brush should use the mask opacity for these enktity types
|
||||||
return { ...selectedEntity.state.fill.color, a: 1 };
|
return { ...selectedEntity.state.fill.color, a: 1 };
|
||||||
} else {
|
} else {
|
||||||
const state = this.getState();
|
return this.getToolState().fill;
|
||||||
return state.tool.fill;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$transformingEntity = atom<CanvasEntityIdentifier | null>(null);
|
$transformingEntity = atom<CanvasEntityIdentifier | null>(null);
|
||||||
$isProcessingTransform = atom<boolean>(false);
|
$isProcessingTransform = atom<boolean>(false);
|
||||||
|
|
||||||
$toolState: WritableAtom<CanvasV2State['tool']> = atom();
|
$toolState: WritableAtom<ToolState> = atom();
|
||||||
$currentFill: WritableAtom<RgbaColor> = atom();
|
$currentFill: WritableAtom<RgbaColor> = atom();
|
||||||
$selectedEntity: WritableAtom<EntityStateAndAdapter | null> = atom();
|
$selectedEntity: WritableAtom<EntityStateAndAdapter | null> = atom();
|
||||||
$selectedEntityIdentifier: WritableAtom<CanvasEntityIdentifier | null> = atom();
|
$selectedEntityIdentifier: WritableAtom<CanvasEntityIdentifier | null> = atom();
|
||||||
|
@ -15,7 +15,6 @@ import { regionsReducers } from 'features/controlLayers/store/regionsReducers';
|
|||||||
import { selectAllEntities, selectAllEntitiesOfType, selectEntity } from 'features/controlLayers/store/selectors';
|
import { selectAllEntities, selectAllEntitiesOfType, selectEntity } from 'features/controlLayers/store/selectors';
|
||||||
import { sessionReducers } from 'features/controlLayers/store/sessionReducers';
|
import { sessionReducers } from 'features/controlLayers/store/sessionReducers';
|
||||||
import { settingsReducers } from 'features/controlLayers/store/settingsReducers';
|
import { settingsReducers } from 'features/controlLayers/store/settingsReducers';
|
||||||
import { toolReducers } from 'features/controlLayers/store/toolReducers';
|
|
||||||
import { getScaledBoundingBoxDimensions } from 'features/controlLayers/util/getScaledBoundingBoxDimensions';
|
import { getScaledBoundingBoxDimensions } from 'features/controlLayers/util/getScaledBoundingBoxDimensions';
|
||||||
import { simplifyFlatNumbersArray } from 'features/controlLayers/util/simplify';
|
import { simplifyFlatNumbersArray } from 'features/controlLayers/util/simplify';
|
||||||
import { calculateNewSize } from 'features/parameters/components/DocumentSize/calculateNewSize';
|
import { calculateNewSize } from 'features/parameters/components/DocumentSize/calculateNewSize';
|
||||||
@ -57,16 +56,6 @@ const initialState: CanvasV2State = {
|
|||||||
},
|
},
|
||||||
loras: [],
|
loras: [],
|
||||||
ipAdapters: { entities: [] },
|
ipAdapters: { entities: [] },
|
||||||
tool: {
|
|
||||||
invertScroll: false,
|
|
||||||
fill: { r: 31, g: 160, b: 224, a: 1 }, // invokeBlue.500
|
|
||||||
brush: {
|
|
||||||
width: 50,
|
|
||||||
},
|
|
||||||
eraser: {
|
|
||||||
width: 50,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
bbox: {
|
bbox: {
|
||||||
rect: { x: 0, y: 0, width: 512, height: 512 },
|
rect: { x: 0, y: 0, width: 512, height: 512 },
|
||||||
optimalDimension: 512,
|
optimalDimension: 512,
|
||||||
@ -109,7 +98,6 @@ export const canvasV2Slice = createSlice({
|
|||||||
// move out
|
// move out
|
||||||
...lorasReducers,
|
...lorasReducers,
|
||||||
...settingsReducers,
|
...settingsReducers,
|
||||||
...toolReducers,
|
|
||||||
...sessionReducers,
|
...sessionReducers,
|
||||||
entitySelected: (state, action: PayloadAction<EntityIdentifierPayload>) => {
|
entitySelected: (state, action: PayloadAction<EntityIdentifierPayload>) => {
|
||||||
const { entityIdentifier } = action.payload;
|
const { entityIdentifier } = action.payload;
|
||||||
@ -364,7 +352,6 @@ export const canvasV2Slice = createSlice({
|
|||||||
const size = pick(state.bbox.rect, 'width', 'height');
|
const size = pick(state.bbox.rect, 'width', 'height');
|
||||||
state.bbox.scaledSize = getScaledBoundingBoxDimensions(size, state.bbox.optimalDimension);
|
state.bbox.scaledSize = getScaledBoundingBoxDimensions(size, state.bbox.optimalDimension);
|
||||||
state.session = deepClone(initialState.session);
|
state.session = deepClone(initialState.session);
|
||||||
state.tool = deepClone(initialState.tool);
|
|
||||||
|
|
||||||
state.ipAdapters = deepClone(initialState.ipAdapters);
|
state.ipAdapters = deepClone(initialState.ipAdapters);
|
||||||
state.rasterLayers = deepClone(initialState.rasterLayers);
|
state.rasterLayers = deepClone(initialState.rasterLayers);
|
||||||
@ -403,10 +390,6 @@ export const canvasV2Slice = createSlice({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const {
|
export const {
|
||||||
brushWidthChanged,
|
|
||||||
eraserWidthChanged,
|
|
||||||
fillChanged,
|
|
||||||
invertScrollChanged,
|
|
||||||
clipToBboxChanged,
|
clipToBboxChanged,
|
||||||
canvasReset,
|
canvasReset,
|
||||||
settingsDynamicGridToggled,
|
settingsDynamicGridToggled,
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
import type { PayloadAction, SliceCaseReducers } from '@reduxjs/toolkit';
|
|
||||||
import type { CanvasV2State, RgbaColor } from 'features/controlLayers/store/types';
|
|
||||||
|
|
||||||
export const toolReducers = {
|
|
||||||
brushWidthChanged: (state, action: PayloadAction<number>) => {
|
|
||||||
state.tool.brush.width = Math.round(action.payload);
|
|
||||||
},
|
|
||||||
eraserWidthChanged: (state, action: PayloadAction<number>) => {
|
|
||||||
state.tool.eraser.width = Math.round(action.payload);
|
|
||||||
},
|
|
||||||
fillChanged: (state, action: PayloadAction<RgbaColor>) => {
|
|
||||||
state.tool.fill = action.payload;
|
|
||||||
},
|
|
||||||
invertScrollChanged: (state, action: PayloadAction<boolean>) => {
|
|
||||||
state.tool.invertScroll = action.payload;
|
|
||||||
},
|
|
||||||
} satisfies SliceCaseReducers<CanvasV2State>;
|
|
@ -0,0 +1,54 @@
|
|||||||
|
import { createSlice, type PayloadAction } from '@reduxjs/toolkit';
|
||||||
|
import type { PersistConfig } from 'app/store/store';
|
||||||
|
import type { RgbaColor } from 'features/controlLayers/store/types';
|
||||||
|
|
||||||
|
export type ToolState = {
|
||||||
|
invertScroll: boolean;
|
||||||
|
brush: { width: number };
|
||||||
|
eraser: { width: number };
|
||||||
|
fill: RgbaColor;
|
||||||
|
};
|
||||||
|
|
||||||
|
const initialState: ToolState = {
|
||||||
|
invertScroll: false,
|
||||||
|
fill: { r: 31, g: 160, b: 224, a: 1 }, // invokeBlue.500
|
||||||
|
brush: {
|
||||||
|
width: 50,
|
||||||
|
},
|
||||||
|
eraser: {
|
||||||
|
width: 50,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const toolSlice = createSlice({
|
||||||
|
name: 'tool',
|
||||||
|
initialState,
|
||||||
|
reducers: {
|
||||||
|
brushWidthChanged: (state, action: PayloadAction<number>) => {
|
||||||
|
state.brush.width = Math.round(action.payload);
|
||||||
|
},
|
||||||
|
eraserWidthChanged: (state, action: PayloadAction<number>) => {
|
||||||
|
state.eraser.width = Math.round(action.payload);
|
||||||
|
},
|
||||||
|
fillChanged: (state, action: PayloadAction<RgbaColor>) => {
|
||||||
|
state.fill = action.payload;
|
||||||
|
},
|
||||||
|
invertScrollChanged: (state, action: PayloadAction<boolean>) => {
|
||||||
|
state.invertScroll = action.payload;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const { brushWidthChanged, eraserWidthChanged, fillChanged, invertScrollChanged } = toolSlice.actions;
|
||||||
|
|
||||||
|
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
||||||
|
const migrate = (state: any): any => {
|
||||||
|
return state;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const toolPersistConfig: PersistConfig<ToolState> = {
|
||||||
|
name: toolSlice.name,
|
||||||
|
initialState,
|
||||||
|
migrate,
|
||||||
|
persistDenylist: [],
|
||||||
|
};
|
@ -715,12 +715,6 @@ export type CanvasV2State = {
|
|||||||
entities: CanvasIPAdapterState[];
|
entities: CanvasIPAdapterState[];
|
||||||
};
|
};
|
||||||
loras: LoRA[];
|
loras: LoRA[];
|
||||||
tool: {
|
|
||||||
invertScroll: boolean;
|
|
||||||
brush: { width: number };
|
|
||||||
eraser: { width: number };
|
|
||||||
fill: RgbaColor;
|
|
||||||
};
|
|
||||||
settings: {
|
settings: {
|
||||||
imageSmoothing: boolean;
|
imageSmoothing: boolean;
|
||||||
showHUD: boolean;
|
showHUD: boolean;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user