mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-02-02 05:15:16 -05:00
feat(ui): streamline manager -> react transform interface
This commit is contained in:
@@ -1,19 +1,14 @@
|
||||
import { Button, ButtonGroup, Flex, Heading, Spacer } from '@invoke-ai/ui-library';
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { useCanvasManager } from 'features/controlLayers/contexts/CanvasManagerProviderGate';
|
||||
import {
|
||||
EntityIdentifierContext,
|
||||
useEntityIdentifierContext,
|
||||
} from 'features/controlLayers/contexts/EntityIdentifierContext';
|
||||
import { useEntityAdapter } from 'features/controlLayers/hooks/useEntityAdapter';
|
||||
import type { CanvasEntityLayerAdapter } from 'features/controlLayers/konva/CanvasEntityLayerAdapter';
|
||||
import type { CanvasEntityMaskAdapter } from 'features/controlLayers/konva/CanvasEntityMaskAdapter';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiArrowsCounterClockwiseBold, PiArrowsOutBold, PiCheckBold, PiXBold } from 'react-icons/pi';
|
||||
|
||||
const TransformBox = memo(() => {
|
||||
const TransformBox = memo(({ adapter }: { adapter: CanvasEntityLayerAdapter | CanvasEntityMaskAdapter }) => {
|
||||
const { t } = useTranslation();
|
||||
const entityIdentifier = useEntityIdentifierContext();
|
||||
const adapter = useEntityAdapter(entityIdentifier);
|
||||
const isProcessing = useStore(adapter.transformer.$isProcessing);
|
||||
|
||||
return (
|
||||
@@ -79,15 +74,11 @@ TransformBox.displayName = 'Transform';
|
||||
|
||||
export const Transform = () => {
|
||||
const canvasManager = useCanvasManager();
|
||||
const transformingEntity = useStore(canvasManager.stateApi.$transformingEntity);
|
||||
const adapter = useStore(canvasManager.stateApi.$transformingAdapter);
|
||||
|
||||
if (!transformingEntity) {
|
||||
if (!adapter) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<EntityIdentifierContext.Provider value={transformingEntity}>
|
||||
<TransformBox />
|
||||
</EntityIdentifierContext.Provider>
|
||||
);
|
||||
return <TransformBox adapter={adapter} />;
|
||||
};
|
||||
|
||||
@@ -12,14 +12,14 @@ export const CanvasEntityMenuItemsTransform = memo(() => {
|
||||
const entityIdentifier = useEntityIdentifierContext();
|
||||
const canvasManager = useCanvasManager();
|
||||
const adapter = useEntityAdapter(entityIdentifier);
|
||||
const transformingEntity = useStore(canvasManager.stateApi.$transformingEntity);
|
||||
const isTransforming = useStore(canvasManager.stateApi.$isTranforming);
|
||||
|
||||
const onClick = useCallback(() => {
|
||||
adapter.transformer.startTransform();
|
||||
}, [adapter.transformer]);
|
||||
|
||||
return (
|
||||
<MenuItem onClick={onClick} icon={<PiFrameCornersBold />} isDisabled={Boolean(transformingEntity)}>
|
||||
<MenuItem onClick={onClick} icon={<PiFrameCornersBold />} isDisabled={isTransforming}>
|
||||
{t('controlLayers.transform.transform')}
|
||||
</MenuItem>
|
||||
);
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useMemo } from 'react';
|
||||
|
||||
export const useIsTransforming = () => {
|
||||
const canvasManager = useCanvasManager();
|
||||
const transformingEntity = useStore(canvasManager.stateApi.$transformingEntity);
|
||||
const transformingEntity = useStore(canvasManager.stateApi.$transformingAdapter);
|
||||
const isTransforming = useMemo(() => {
|
||||
return Boolean(transformingEntity);
|
||||
}, [transformingEntity]);
|
||||
|
||||
@@ -573,7 +573,7 @@ export class CanvasEntityTransformer extends CanvasModuleBase {
|
||||
const shouldListen = this.manager.stateApi.$tool.get() !== 'view';
|
||||
this.parent.konva.layer.listening(shouldListen);
|
||||
this.setInteractionMode('all');
|
||||
this.manager.stateApi.$transformingEntity.set(this.parent.getEntityIdentifier());
|
||||
this.manager.stateApi.$transformingAdapter.set(this.parent);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -608,7 +608,7 @@ export class CanvasEntityTransformer extends CanvasModuleBase {
|
||||
// canceled a transformation. In either case, the scale should be reset.
|
||||
this.resetTransform();
|
||||
this.syncInteractionState();
|
||||
this.manager.stateApi.$transformingEntity.set(null);
|
||||
this.manager.stateApi.$transformingAdapter.set(null);
|
||||
this.$isProcessing.set(false);
|
||||
};
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@ export class CanvasManager extends CanvasModuleBase {
|
||||
this.log.debug('Initializing canvas manager module');
|
||||
|
||||
// These atoms require the canvas manager to be set up before we can provide their initial values
|
||||
this.stateApi.$transformingEntity.set(null);
|
||||
this.stateApi.$transformingAdapter.set(null);
|
||||
this.stateApi.$toolState.set(this.stateApi.getToolState());
|
||||
this.stateApi.$selectedEntityIdentifier.set(this.stateApi.getCanvasState().selectedEntityIdentifier);
|
||||
this.stateApi.$currentFill.set(this.stateApi.getCurrentFill());
|
||||
|
||||
@@ -43,7 +43,7 @@ import type {
|
||||
} from 'features/controlLayers/store/types';
|
||||
import { RGBA_BLACK } from 'features/controlLayers/store/types';
|
||||
import type { WritableAtom } from 'nanostores';
|
||||
import { atom } from 'nanostores';
|
||||
import { atom, computed } from 'nanostores';
|
||||
import type { Logger } from 'roarr';
|
||||
import { queueApi } from 'services/api/endpoints/queue';
|
||||
import type { BatchConfig } from 'services/api/types';
|
||||
@@ -245,7 +245,8 @@ export class CanvasStateApiModule extends CanvasModuleBase {
|
||||
}
|
||||
};
|
||||
|
||||
$transformingEntity = atom<CanvasEntityIdentifier | null>(null);
|
||||
$transformingAdapter = atom<CanvasEntityLayerAdapter | CanvasEntityMaskAdapter | null>(null);
|
||||
$isTranforming = computed(this.$transformingAdapter, (transformingAdapter) => Boolean(transformingAdapter));
|
||||
|
||||
$toolState: WritableAtom<ToolState> = atom();
|
||||
$currentFill: WritableAtom<RgbaColor> = atom();
|
||||
|
||||
@@ -119,7 +119,7 @@ export class CanvasToolModule extends CanvasModuleBase {
|
||||
isDrawableEntity(selectedEntity.state);
|
||||
|
||||
// Update the stage's pointer style
|
||||
if (Boolean(this.manager.stateApi.$transformingEntity.get()) || renderedEntityCount === 0) {
|
||||
if (this.manager.stateApi.$isTranforming.get() || renderedEntityCount === 0) {
|
||||
// We are transforming and/or have no layers, so we should not render any tool
|
||||
stage.container.style.cursor = 'default';
|
||||
} else if (tool === 'view') {
|
||||
|
||||
Reference in New Issue
Block a user