mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): move ephemeral state into canvas classes
Things like `$lastCursorPos` are now created within the canvas drawing classes. Consumers in react access them via `useCanvasManager`. For example: ```tsx const canvasManager = useCanvasManager(); const lastCursorPos = useStore(canvasManager.stateApi.$lastCursorPos); ```
This commit is contained in:
parent
c624754404
commit
cdd8b60fd0
@ -14,10 +14,9 @@ import {
|
|||||||
PopoverTrigger,
|
PopoverTrigger,
|
||||||
} from '@invoke-ai/ui-library';
|
} from '@invoke-ai/ui-library';
|
||||||
import { useStore } from '@nanostores/react';
|
import { useStore } from '@nanostores/react';
|
||||||
import { $canvasManager } from 'features/controlLayers/konva/CanvasManager';
|
import { useCanvasManager } from 'features/controlLayers/contexts/CanvasManagerProviderGate';
|
||||||
import { MAX_CANVAS_SCALE, MIN_CANVAS_SCALE } from 'features/controlLayers/konva/constants';
|
import { MAX_CANVAS_SCALE, MIN_CANVAS_SCALE } from 'features/controlLayers/konva/constants';
|
||||||
import { snapToNearest } from 'features/controlLayers/konva/util';
|
import { snapToNearest } from 'features/controlLayers/konva/util';
|
||||||
import { $stageAttrs } from 'features/controlLayers/store/canvasV2Slice';
|
|
||||||
import { clamp, round } from 'lodash-es';
|
import { clamp, round } from 'lodash-es';
|
||||||
import { computed } from 'nanostores';
|
import { computed } from 'nanostores';
|
||||||
import type { KeyboardEvent } from 'react';
|
import type { KeyboardEvent } from 'react';
|
||||||
@ -72,12 +71,10 @@ const sliderDefaultValue = mapScaleToSliderValue(100);
|
|||||||
|
|
||||||
const snapCandidates = marks.slice(1, marks.length - 1);
|
const snapCandidates = marks.slice(1, marks.length - 1);
|
||||||
|
|
||||||
const $scale = computed($stageAttrs, (attrs) => attrs.scale);
|
|
||||||
|
|
||||||
export const CanvasScale = memo(() => {
|
export const CanvasScale = memo(() => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const canvasManager = useStore($canvasManager);
|
const canvasManager = useCanvasManager();
|
||||||
const scale = useStore($scale);
|
const scale = useStore(computed(canvasManager.stateApi.$stageAttrs, (attrs) => attrs.scale));
|
||||||
const [localScale, setLocalScale] = useState(scale * 100);
|
const [localScale, setLocalScale] = useState(scale * 100);
|
||||||
|
|
||||||
const onChangeSlider = useCallback(
|
const onChangeSlider = useCallback(
|
||||||
|
@ -1,24 +1,18 @@
|
|||||||
import { Box, Flex, Text } from '@invoke-ai/ui-library';
|
import { Box, Flex, Text } from '@invoke-ai/ui-library';
|
||||||
import { useStore } from '@nanostores/react';
|
import { useStore } from '@nanostores/react';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import {
|
import { useCanvasManager } from 'features/controlLayers/contexts/CanvasManagerProviderGate';
|
||||||
$isDrawing,
|
|
||||||
$isMouseDown,
|
|
||||||
$lastAddedPoint,
|
|
||||||
$lastCursorPos,
|
|
||||||
$lastMouseDownPos,
|
|
||||||
$stageAttrs,
|
|
||||||
} from 'features/controlLayers/store/canvasV2Slice';
|
|
||||||
import { round } from 'lodash-es';
|
import { round } from 'lodash-es';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
|
||||||
export const HeadsUpDisplay = memo(() => {
|
export const HeadsUpDisplay = memo(() => {
|
||||||
const stageAttrs = useStore($stageAttrs);
|
const canvasManager = useCanvasManager();
|
||||||
const cursorPos = useStore($lastCursorPos);
|
const stageAttrs = useStore(canvasManager.stateApi.$stageAttrs);
|
||||||
const isDrawing = useStore($isDrawing);
|
const cursorPos = useStore(canvasManager.stateApi.$lastCursorPos);
|
||||||
const isMouseDown = useStore($isMouseDown);
|
const isDrawing = useStore(canvasManager.stateApi.$isDrawing);
|
||||||
const lastMouseDownPos = useStore($lastMouseDownPos);
|
const isMouseDown = useStore(canvasManager.stateApi.$isMouseDown);
|
||||||
const lastAddedPoint = useStore($lastAddedPoint);
|
const lastMouseDownPos = useStore(canvasManager.stateApi.$lastMouseDownPos);
|
||||||
|
const lastAddedPoint = useStore(canvasManager.stateApi.$lastAddedPoint);
|
||||||
const bbox = useAppSelector((s) => s.canvasV2.bbox);
|
const bbox = useAppSelector((s) => s.canvasV2.bbox);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -2,8 +2,8 @@ import { Button, ButtonGroup, IconButton } from '@invoke-ai/ui-library';
|
|||||||
import { useStore } from '@nanostores/react';
|
import { useStore } from '@nanostores/react';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { INTERACTION_SCOPES, useScopeOnMount } from 'common/hooks/interactionScopes';
|
import { INTERACTION_SCOPES, useScopeOnMount } from 'common/hooks/interactionScopes';
|
||||||
|
import { useCanvasManager } from 'features/controlLayers/contexts/CanvasManagerProviderGate';
|
||||||
import {
|
import {
|
||||||
$shouldShowStagedImage,
|
|
||||||
sessionNextStagedImageSelected,
|
sessionNextStagedImageSelected,
|
||||||
sessionPrevStagedImageSelected,
|
sessionPrevStagedImageSelected,
|
||||||
sessionStagedImageDiscarded,
|
sessionStagedImageDiscarded,
|
||||||
@ -28,7 +28,8 @@ import { useChangeImageIsIntermediateMutation } from 'services/api/endpoints/ima
|
|||||||
export const StagingAreaToolbar = memo(() => {
|
export const StagingAreaToolbar = memo(() => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const session = useAppSelector((s) => s.canvasV2.session);
|
const session = useAppSelector((s) => s.canvasV2.session);
|
||||||
const shouldShowStagedImage = useStore($shouldShowStagedImage);
|
const canvasManager = useCanvasManager();
|
||||||
|
const shouldShowStagedImage = useStore(canvasManager.stateApi.$shouldShowStagedImage);
|
||||||
const images = useMemo(() => session.stagedImages, [session]);
|
const images = useMemo(() => session.stagedImages, [session]);
|
||||||
const selectedImage = useMemo(() => {
|
const selectedImage = useMemo(() => {
|
||||||
return images[session.selectedStagedImageIndex] ?? null;
|
return images[session.selectedStagedImageIndex] ?? null;
|
||||||
@ -70,8 +71,8 @@ export const StagingAreaToolbar = memo(() => {
|
|||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
|
||||||
const onToggleShouldShowStagedImage = useCallback(() => {
|
const onToggleShouldShowStagedImage = useCallback(() => {
|
||||||
$shouldShowStagedImage.set(!shouldShowStagedImage);
|
canvasManager.stateApi.$shouldShowStagedImage.set(!shouldShowStagedImage);
|
||||||
}, [shouldShowStagedImage]);
|
}, [canvasManager.stateApi.$shouldShowStagedImage, shouldShowStagedImage]);
|
||||||
|
|
||||||
const onSaveStagingImage = useCallback(() => {
|
const onSaveStagingImage = useCallback(() => {
|
||||||
if (!selectedImage) {
|
if (!selectedImage) {
|
||||||
|
@ -4,16 +4,6 @@ import type { CanvasLayerAdapter } from 'features/controlLayers/konva/CanvasLaye
|
|||||||
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
||||||
import type { CanvasMaskAdapter } from 'features/controlLayers/konva/CanvasMaskAdapter';
|
import type { CanvasMaskAdapter } from 'features/controlLayers/konva/CanvasMaskAdapter';
|
||||||
import {
|
import {
|
||||||
$isDrawing,
|
|
||||||
$isMouseDown,
|
|
||||||
$isProcessingTransform,
|
|
||||||
$lastAddedPoint,
|
|
||||||
$lastCursorPos,
|
|
||||||
$lastMouseDownPos,
|
|
||||||
$shouldShowStagedImage,
|
|
||||||
$spaceKey,
|
|
||||||
$stageAttrs,
|
|
||||||
$transformingEntity,
|
|
||||||
bboxChanged,
|
bboxChanged,
|
||||||
brushWidthChanged,
|
brushWidthChanged,
|
||||||
entityBrushLineAdded,
|
entityBrushLineAdded,
|
||||||
@ -36,6 +26,7 @@ import type {
|
|||||||
CanvasRasterLayerState,
|
CanvasRasterLayerState,
|
||||||
CanvasRegionalGuidanceState,
|
CanvasRegionalGuidanceState,
|
||||||
CanvasV2State,
|
CanvasV2State,
|
||||||
|
Coordinate,
|
||||||
EntityBrushLineAddedPayload,
|
EntityBrushLineAddedPayload,
|
||||||
EntityEraserLineAddedPayload,
|
EntityEraserLineAddedPayload,
|
||||||
EntityIdentifierPayload,
|
EntityIdentifierPayload,
|
||||||
@ -45,6 +36,7 @@ import type {
|
|||||||
Rect,
|
Rect,
|
||||||
RgbaColor,
|
RgbaColor,
|
||||||
RgbColor,
|
RgbColor,
|
||||||
|
StageAttrs,
|
||||||
Tool,
|
Tool,
|
||||||
} from 'features/controlLayers/store/types';
|
} from 'features/controlLayers/store/types';
|
||||||
import { RGBA_BLACK } from 'features/controlLayers/store/types';
|
import { RGBA_BLACK } from 'features/controlLayers/store/types';
|
||||||
@ -243,8 +235,8 @@ export class CanvasStateApiModule {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$transformingEntity = $transformingEntity;
|
$transformingEntity = atom<CanvasEntityIdentifier | null>(null);
|
||||||
$isProcessingTransform = $isProcessingTransform;
|
$isProcessingTransform = atom<boolean>(false);
|
||||||
|
|
||||||
$toolState: WritableAtom<CanvasV2State['tool']> = atom();
|
$toolState: WritableAtom<CanvasV2State['tool']> = atom();
|
||||||
$currentFill: WritableAtom<RgbaColor> = atom();
|
$currentFill: WritableAtom<RgbaColor> = atom();
|
||||||
@ -253,17 +245,23 @@ export class CanvasStateApiModule {
|
|||||||
$colorUnderCursor: WritableAtom<RgbColor> = atom(RGBA_BLACK);
|
$colorUnderCursor: WritableAtom<RgbColor> = atom(RGBA_BLACK);
|
||||||
|
|
||||||
// Read-write state, ephemeral interaction state
|
// Read-write state, ephemeral interaction state
|
||||||
$isDrawing = $isDrawing;
|
$isDrawing = atom<boolean>(false);
|
||||||
$isMouseDown = $isMouseDown;
|
$isMouseDown = atom<boolean>(false);
|
||||||
$lastAddedPoint = $lastAddedPoint;
|
$lastAddedPoint = atom<Coordinate | null>(null);
|
||||||
$lastMouseDownPos = $lastMouseDownPos;
|
$lastMouseDownPos = atom<Coordinate | null>(null);
|
||||||
$lastCursorPos = $lastCursorPos;
|
$lastCursorPos = atom<Coordinate | null>(null);
|
||||||
$lastCanvasProgressEvent = $lastCanvasProgressEvent;
|
$lastCanvasProgressEvent = $lastCanvasProgressEvent;
|
||||||
$spaceKey = $spaceKey;
|
$spaceKey = atom<boolean>(false);
|
||||||
$altKey = $alt;
|
$altKey = $alt;
|
||||||
$ctrlKey = $ctrl;
|
$ctrlKey = $ctrl;
|
||||||
$metaKey = $meta;
|
$metaKey = $meta;
|
||||||
$shiftKey = $shift;
|
$shiftKey = $shift;
|
||||||
$shouldShowStagedImage = $shouldShowStagedImage;
|
$shouldShowStagedImage = atom(true);
|
||||||
$stageAttrs = $stageAttrs;
|
$stageAttrs = atom<StageAttrs>({
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
scale: 0,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -22,20 +22,17 @@ import { simplifyFlatNumbersArray } from 'features/controlLayers/util/simplify';
|
|||||||
import { initialAspectRatioState } from 'features/parameters/components/DocumentSize/constants';
|
import { initialAspectRatioState } from 'features/parameters/components/DocumentSize/constants';
|
||||||
import { getOptimalDimension } from 'features/parameters/util/optimalDimension';
|
import { getOptimalDimension } from 'features/parameters/util/optimalDimension';
|
||||||
import { pick } from 'lodash-es';
|
import { pick } from 'lodash-es';
|
||||||
import { atom } from 'nanostores';
|
|
||||||
import { assert } from 'tsafe';
|
import { assert } from 'tsafe';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
CanvasEntityIdentifier,
|
CanvasEntityIdentifier,
|
||||||
CanvasV2State,
|
CanvasV2State,
|
||||||
Coordinate,
|
|
||||||
EntityBrushLineAddedPayload,
|
EntityBrushLineAddedPayload,
|
||||||
EntityEraserLineAddedPayload,
|
EntityEraserLineAddedPayload,
|
||||||
EntityIdentifierPayload,
|
EntityIdentifierPayload,
|
||||||
EntityMovedPayload,
|
EntityMovedPayload,
|
||||||
EntityRasterizedPayload,
|
EntityRasterizedPayload,
|
||||||
EntityRectAddedPayload,
|
EntityRectAddedPayload,
|
||||||
StageAttrs,
|
|
||||||
} from './types';
|
} from './types';
|
||||||
import { getEntityIdentifier, isDrawableEntity } from './types';
|
import { getEntityIdentifier, isDrawableEntity } from './types';
|
||||||
|
|
||||||
@ -564,25 +561,6 @@ const migrate = (state: any): any => {
|
|||||||
return state;
|
return state;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Ephemeral state that does not need to be in redux
|
|
||||||
export const $isPreviewVisible = atom(true);
|
|
||||||
export const $stageAttrs = atom<StageAttrs>({
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
width: 0,
|
|
||||||
height: 0,
|
|
||||||
scale: 0,
|
|
||||||
});
|
|
||||||
export const $shouldShowStagedImage = atom(true);
|
|
||||||
export const $isDrawing = atom<boolean>(false);
|
|
||||||
export const $isMouseDown = atom<boolean>(false);
|
|
||||||
export const $lastAddedPoint = atom<Coordinate | null>(null);
|
|
||||||
export const $lastMouseDownPos = atom<Coordinate | null>(null);
|
|
||||||
export const $lastCursorPos = atom<Coordinate | null>(null);
|
|
||||||
export const $spaceKey = atom<boolean>(false);
|
|
||||||
export const $transformingEntity = atom<CanvasEntityIdentifier | null>(null);
|
|
||||||
export const $isProcessingTransform = atom<boolean>(false);
|
|
||||||
|
|
||||||
export const canvasV2PersistConfig: PersistConfig<CanvasV2State> = {
|
export const canvasV2PersistConfig: PersistConfig<CanvasV2State> = {
|
||||||
name: canvasV2Slice.name,
|
name: canvasV2Slice.name,
|
||||||
initialState,
|
initialState,
|
||||||
|
@ -5,7 +5,6 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|||||||
import { overlayScrollbarsParams } from 'common/components/OverlayScrollbars/constants';
|
import { overlayScrollbarsParams } from 'common/components/OverlayScrollbars/constants';
|
||||||
import { CanvasEntityListMenuButton } from 'features/controlLayers/components/CanvasEntityList/CanvasEntityListMenuButton';
|
import { CanvasEntityListMenuButton } from 'features/controlLayers/components/CanvasEntityList/CanvasEntityListMenuButton';
|
||||||
import { CanvasPanelContent } from 'features/controlLayers/components/CanvasPanelContent';
|
import { CanvasPanelContent } from 'features/controlLayers/components/CanvasPanelContent';
|
||||||
import { $isPreviewVisible } from 'features/controlLayers/store/canvasV2Slice';
|
|
||||||
import { selectEntityCount } from 'features/controlLayers/store/selectors';
|
import { selectEntityCount } from 'features/controlLayers/store/selectors';
|
||||||
import { isImageViewerOpenChanged } from 'features/gallery/store/gallerySlice';
|
import { isImageViewerOpenChanged } from 'features/gallery/store/gallerySlice';
|
||||||
import { Prompts } from 'features/parameters/components/Prompts/Prompts';
|
import { Prompts } from 'features/parameters/components/Prompts/Prompts';
|
||||||
@ -56,7 +55,6 @@ const ParametersPanelTextToImage = () => {
|
|||||||
if (i === 1) {
|
if (i === 1) {
|
||||||
dispatch(isImageViewerOpenChanged(false));
|
dispatch(isImageViewerOpenChanged(false));
|
||||||
}
|
}
|
||||||
$isPreviewVisible.set(i === 0);
|
|
||||||
},
|
},
|
||||||
[dispatch]
|
[dispatch]
|
||||||
);
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user