mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): rip out document size
barely knew ye
This commit is contained in:
parent
22ab63fe8d
commit
c3c95754f7
@ -3,9 +3,9 @@ import type { AppStartListening } from 'app/store/middleware/listenerMiddleware'
|
|||||||
import type { AppDispatch, RootState } from 'app/store/store';
|
import type { AppDispatch, RootState } from 'app/store/store';
|
||||||
import type { JSONObject } from 'common/types';
|
import type { JSONObject } from 'common/types';
|
||||||
import {
|
import {
|
||||||
|
bboxHeightChanged,
|
||||||
|
bboxWidthChanged,
|
||||||
caModelChanged,
|
caModelChanged,
|
||||||
documentHeightChanged,
|
|
||||||
documentWidthChanged,
|
|
||||||
ipaModelChanged,
|
ipaModelChanged,
|
||||||
loraDeleted,
|
loraDeleted,
|
||||||
modelChanged,
|
modelChanged,
|
||||||
@ -83,16 +83,16 @@ const handleMainModels: ModelHandler = (models, state, dispatch, log) => {
|
|||||||
dispatch(modelChanged({ model: defaultModelInList, previousModel: currentModel }));
|
dispatch(modelChanged({ model: defaultModelInList, previousModel: currentModel }));
|
||||||
|
|
||||||
const optimalDimension = getOptimalDimension(defaultModelInList);
|
const optimalDimension = getOptimalDimension(defaultModelInList);
|
||||||
if (getIsSizeOptimal(state.canvasV2.document.rect.width, state.canvasV2.document.rect.height, optimalDimension)) {
|
if (getIsSizeOptimal(state.canvasV2.bbox.rect.width, state.canvasV2.bbox.rect.height, optimalDimension)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { width, height } = calculateNewSize(
|
const { width, height } = calculateNewSize(
|
||||||
state.canvasV2.document.aspectRatio.value,
|
state.canvasV2.bbox.aspectRatio.value,
|
||||||
optimalDimension * optimalDimension
|
optimalDimension * optimalDimension
|
||||||
);
|
);
|
||||||
|
|
||||||
dispatch(documentWidthChanged({ width }));
|
dispatch(bboxWidthChanged({ width }));
|
||||||
dispatch(documentHeightChanged({ height }));
|
dispatch(bboxHeightChanged({ height }));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import type { AppStartListening } from 'app/store/middleware/listenerMiddleware';
|
import type { AppStartListening } from 'app/store/middleware/listenerMiddleware';
|
||||||
import {
|
import {
|
||||||
documentHeightChanged,
|
bboxHeightChanged,
|
||||||
documentWidthChanged,
|
bboxWidthChanged,
|
||||||
setCfgRescaleMultiplier,
|
setCfgRescaleMultiplier,
|
||||||
setCfgScale,
|
setCfgScale,
|
||||||
setScheduler,
|
setScheduler,
|
||||||
@ -99,13 +99,13 @@ export const addSetDefaultSettingsListener = (startAppListening: AppStartListeni
|
|||||||
const setSizeOptions = { updateAspectRatio: true, clamp: true };
|
const setSizeOptions = { updateAspectRatio: true, clamp: true };
|
||||||
if (width) {
|
if (width) {
|
||||||
if (isParameterWidth(width)) {
|
if (isParameterWidth(width)) {
|
||||||
dispatch(documentWidthChanged({ width, ...setSizeOptions }));
|
dispatch(bboxWidthChanged({ width, ...setSizeOptions }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (height) {
|
if (height) {
|
||||||
if (isParameterHeight(height)) {
|
if (isParameterHeight(height)) {
|
||||||
dispatch(documentHeightChanged({ height, ...setSizeOptions }));
|
dispatch(bboxHeightChanged({ height, ...setSizeOptions }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ type ResizeDirection =
|
|||||||
| 'down-right';
|
| 'down-right';
|
||||||
|
|
||||||
export const CanvasResizer = memo(() => {
|
export const CanvasResizer = memo(() => {
|
||||||
const document = useAppSelector((s) => s.canvasV2.document);
|
const bbox = useAppSelector((s) => s.canvasV2.bbox);
|
||||||
const [resizeDirection, setResizeDirection] = useState<ResizeDirection>('center-out');
|
const [resizeDirection, setResizeDirection] = useState<ResizeDirection>('center-out');
|
||||||
|
|
||||||
const setDirUpLeft = useCallback(() => {
|
const setDirUpLeft = useCallback(() => {
|
||||||
|
@ -3,7 +3,7 @@ import { skipToken } from '@reduxjs/toolkit/query';
|
|||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAIDndImage from 'common/components/IAIDndImage';
|
import IAIDndImage from 'common/components/IAIDndImage';
|
||||||
import IAIDndImageIcon from 'common/components/IAIDndImageIcon';
|
import IAIDndImageIcon from 'common/components/IAIDndImageIcon';
|
||||||
import { documentHeightChanged, documentWidthChanged } from 'features/controlLayers/store/canvasV2Slice';
|
import { bboxHeightChanged, bboxWidthChanged } from 'features/controlLayers/store/canvasV2Slice';
|
||||||
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
||||||
import type { ControlAdapterEntity } from 'features/controlLayers/store/types';
|
import type { ControlAdapterEntity } from 'features/controlLayers/store/types';
|
||||||
import type { ImageDraggableData, TypesafeDroppableData } from 'features/dnd/types';
|
import type { ImageDraggableData, TypesafeDroppableData } from 'features/dnd/types';
|
||||||
@ -89,15 +89,15 @@ export const CAImagePreview = memo(
|
|||||||
|
|
||||||
if (shift) {
|
if (shift) {
|
||||||
const { width, height } = controlImage;
|
const { width, height } = controlImage;
|
||||||
dispatch(documentWidthChanged({ width, ...options }));
|
dispatch(bboxWidthChanged({ width, ...options }));
|
||||||
dispatch(documentHeightChanged({ height, ...options }));
|
dispatch(bboxHeightChanged({ height, ...options }));
|
||||||
} else {
|
} else {
|
||||||
const { width, height } = calculateNewSize(
|
const { width, height } = calculateNewSize(
|
||||||
controlImage.width / controlImage.height,
|
controlImage.width / controlImage.height,
|
||||||
optimalDimension * optimalDimension
|
optimalDimension * optimalDimension
|
||||||
);
|
);
|
||||||
dispatch(documentWidthChanged({ width, ...options }));
|
dispatch(bboxWidthChanged({ width, ...options }));
|
||||||
dispatch(documentHeightChanged({ height, ...options }));
|
dispatch(bboxHeightChanged({ height, ...options }));
|
||||||
}
|
}
|
||||||
}, [controlImage, dispatch, optimalDimension, shift]);
|
}, [controlImage, dispatch, optimalDimension, shift]);
|
||||||
|
|
||||||
|
@ -20,12 +20,10 @@ export const HeadsUpDisplay = memo(() => {
|
|||||||
const lastMouseDownPos = useStore($lastMouseDownPos);
|
const lastMouseDownPos = useStore($lastMouseDownPos);
|
||||||
const lastAddedPoint = useStore($lastAddedPoint);
|
const lastAddedPoint = useStore($lastAddedPoint);
|
||||||
const bbox = useAppSelector((s) => s.canvasV2.bbox);
|
const bbox = useAppSelector((s) => s.canvasV2.bbox);
|
||||||
const document = useAppSelector((s) => s.canvasV2.document);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex flexDir="column" bg="blackAlpha.400" borderBottomEndRadius="base" p={2} minW={64} gap={2}>
|
<Flex flexDir="column" bg="blackAlpha.400" borderBottomEndRadius="base" p={2} minW={64} gap={2}>
|
||||||
<HUDItem label="Zoom" value={`${round(stageAttrs.scale * 100, 2)}%`} />
|
<HUDItem label="Zoom" value={`${round(stageAttrs.scale * 100, 2)}%`} />
|
||||||
<HUDItem label="Document Size" value={`${document.rect.width}×${document.rect.height} px`} />
|
|
||||||
<HUDItem label="Stage Pos" value={`${round(stageAttrs.x, 3)}, ${round(stageAttrs.y, 3)}`} />
|
<HUDItem label="Stage Pos" value={`${round(stageAttrs.x, 3)}, ${round(stageAttrs.y, 3)}`} />
|
||||||
<HUDItem
|
<HUDItem
|
||||||
label="Stage Size"
|
label="Stage Size"
|
||||||
|
@ -3,7 +3,7 @@ import { skipToken } from '@reduxjs/toolkit/query';
|
|||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAIDndImage from 'common/components/IAIDndImage';
|
import IAIDndImage from 'common/components/IAIDndImage';
|
||||||
import IAIDndImageIcon from 'common/components/IAIDndImageIcon';
|
import IAIDndImageIcon from 'common/components/IAIDndImageIcon';
|
||||||
import { documentHeightChanged, documentWidthChanged } from 'features/controlLayers/store/canvasV2Slice';
|
import { bboxHeightChanged, bboxWidthChanged } from 'features/controlLayers/store/canvasV2Slice';
|
||||||
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
||||||
import type { ImageWithDims } from 'features/controlLayers/store/types';
|
import type { ImageWithDims } from 'features/controlLayers/store/types';
|
||||||
import type { ImageDraggableData, TypesafeDroppableData } from 'features/dnd/types';
|
import type { ImageDraggableData, TypesafeDroppableData } from 'features/dnd/types';
|
||||||
@ -42,15 +42,15 @@ export const IPAImagePreview = memo(({ image, onChangeImage, ipAdapterId, droppa
|
|||||||
const options = { updateAspectRatio: true, clamp: true };
|
const options = { updateAspectRatio: true, clamp: true };
|
||||||
if (shift) {
|
if (shift) {
|
||||||
const { width, height } = controlImage;
|
const { width, height } = controlImage;
|
||||||
dispatch(documentWidthChanged({ width, ...options }));
|
dispatch(bboxWidthChanged({ width, ...options }));
|
||||||
dispatch(documentHeightChanged({ height, ...options }));
|
dispatch(bboxHeightChanged({ height, ...options }));
|
||||||
} else {
|
} else {
|
||||||
const { width, height } = calculateNewSize(
|
const { width, height } = calculateNewSize(
|
||||||
controlImage.width / controlImage.height,
|
controlImage.width / controlImage.height,
|
||||||
optimalDimension * optimalDimension
|
optimalDimension * optimalDimension
|
||||||
);
|
);
|
||||||
dispatch(documentWidthChanged({ width, ...options }));
|
dispatch(bboxWidthChanged({ width, ...options }));
|
||||||
dispatch(documentHeightChanged({ height, ...options }));
|
dispatch(bboxHeightChanged({ height, ...options }));
|
||||||
}
|
}
|
||||||
}, [controlImage, dispatch, optimalDimension, shift]);
|
}, [controlImage, dispatch, optimalDimension, shift]);
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import { skipToken } from '@reduxjs/toolkit/query';
|
|||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAIDndImage from 'common/components/IAIDndImage';
|
import IAIDndImage from 'common/components/IAIDndImage';
|
||||||
import IAIDndImageIcon from 'common/components/IAIDndImageIcon';
|
import IAIDndImageIcon from 'common/components/IAIDndImageIcon';
|
||||||
import { documentHeightChanged, documentWidthChanged, iiReset } from 'features/controlLayers/store/canvasV2Slice';
|
import { bboxHeightChanged, bboxWidthChanged, iiReset } from 'features/controlLayers/store/canvasV2Slice';
|
||||||
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
||||||
import type { ImageDraggableData, InitialImageDropData } from 'features/dnd/types';
|
import type { ImageDraggableData, InitialImageDropData } from 'features/dnd/types';
|
||||||
import { calculateNewSize } from 'features/parameters/components/DocumentSize/calculateNewSize';
|
import { calculateNewSize } from 'features/parameters/components/DocumentSize/calculateNewSize';
|
||||||
@ -36,12 +36,12 @@ export const InitialImagePreview = memo(() => {
|
|||||||
const options = { updateAspectRatio: true, clamp: true };
|
const options = { updateAspectRatio: true, clamp: true };
|
||||||
if (shift) {
|
if (shift) {
|
||||||
const { width, height } = imageDTO;
|
const { width, height } = imageDTO;
|
||||||
dispatch(documentWidthChanged({ width, ...options }));
|
dispatch(bboxWidthChanged({ width, ...options }));
|
||||||
dispatch(documentHeightChanged({ height, ...options }));
|
dispatch(bboxHeightChanged({ height, ...options }));
|
||||||
} else {
|
} else {
|
||||||
const { width, height } = calculateNewSize(imageDTO.width / imageDTO.height, optimalDimension * optimalDimension);
|
const { width, height } = calculateNewSize(imageDTO.width / imageDTO.height, optimalDimension * optimalDimension);
|
||||||
dispatch(documentWidthChanged({ width, ...options }));
|
dispatch(bboxWidthChanged({ width, ...options }));
|
||||||
dispatch(documentHeightChanged({ height, ...options }));
|
dispatch(bboxHeightChanged({ height, ...options }));
|
||||||
}
|
}
|
||||||
}, [imageDTO, dispatch, optimalDimension, shift]);
|
}, [imageDTO, dispatch, optimalDimension, shift]);
|
||||||
|
|
||||||
|
@ -1,67 +0,0 @@
|
|||||||
import { getArbitraryBaseColor } from '@invoke-ai/ui-library';
|
|
||||||
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
|
||||||
import { DOCUMENT_FIT_PADDING_PX } from 'features/controlLayers/konva/constants';
|
|
||||||
import Konva from 'konva';
|
|
||||||
|
|
||||||
export class CanvasDocumentSizeOverlay {
|
|
||||||
group: Konva.Group;
|
|
||||||
outerRect: Konva.Rect;
|
|
||||||
innerRect: Konva.Rect;
|
|
||||||
padding: number;
|
|
||||||
manager: CanvasManager;
|
|
||||||
|
|
||||||
constructor(manager: CanvasManager, padding?: number) {
|
|
||||||
this.manager = manager;
|
|
||||||
this.padding = padding ?? DOCUMENT_FIT_PADDING_PX;
|
|
||||||
this.group = new Konva.Group({ id: 'document_overlay_group', listening: false });
|
|
||||||
this.outerRect = new Konva.Rect({
|
|
||||||
id: 'document_overlay_outer_rect',
|
|
||||||
listening: false,
|
|
||||||
fill: getArbitraryBaseColor(10),
|
|
||||||
opacity: 0.7,
|
|
||||||
});
|
|
||||||
this.innerRect = new Konva.Rect({
|
|
||||||
id: 'document_overlay_inner_rect',
|
|
||||||
listening: false,
|
|
||||||
fill: 'white',
|
|
||||||
globalCompositeOperation: 'destination-out',
|
|
||||||
});
|
|
||||||
this.group.add(this.outerRect);
|
|
||||||
this.group.add(this.innerRect);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const document = this.manager.stateApi.getDocument();
|
|
||||||
this.group.zIndex(0);
|
|
||||||
|
|
||||||
const x = this.manager.stage.x();
|
|
||||||
const y = this.manager.stage.y();
|
|
||||||
const width = this.manager.stage.width();
|
|
||||||
const height = this.manager.stage.height();
|
|
||||||
const scale = this.manager.stage.scaleX();
|
|
||||||
|
|
||||||
this.outerRect.setAttrs({
|
|
||||||
offsetX: x / scale,
|
|
||||||
offsetY: y / scale,
|
|
||||||
width: width / scale,
|
|
||||||
height: height / scale,
|
|
||||||
});
|
|
||||||
|
|
||||||
this.innerRect.setAttrs(document.rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
fitToStage() {
|
|
||||||
const document = this.manager.stateApi.getDocument();
|
|
||||||
|
|
||||||
// Fit & center the document on the stage
|
|
||||||
const width = this.manager.stage.width();
|
|
||||||
const height = this.manager.stage.height();
|
|
||||||
const docWidthWithBuffer = document.rect.width + this.padding * 2;
|
|
||||||
const docHeightWithBuffer = document.rect.height + this.padding * 2;
|
|
||||||
const scale = Math.min(Math.min(width / docWidthWithBuffer, height / docHeightWithBuffer), 1);
|
|
||||||
const x = (width - docWidthWithBuffer * scale) / 2 + this.padding * scale;
|
|
||||||
const y = (height - docHeightWithBuffer * scale) / 2 + this.padding * scale;
|
|
||||||
this.manager.stage.setAttrs({ x, y, width, height, scaleX: scale, scaleY: scale });
|
|
||||||
this.manager.stateApi.setStageAttrs({ x, y, width, height, scale });
|
|
||||||
}
|
|
||||||
}
|
|
@ -22,7 +22,6 @@ import { assert } from 'tsafe';
|
|||||||
import { CanvasBackground } from './CanvasBackground';
|
import { CanvasBackground } from './CanvasBackground';
|
||||||
import { CanvasBbox } from './CanvasBbox';
|
import { CanvasBbox } from './CanvasBbox';
|
||||||
import { CanvasControlAdapter } from './CanvasControlAdapter';
|
import { CanvasControlAdapter } from './CanvasControlAdapter';
|
||||||
import { CanvasDocumentSizeOverlay } from './CanvasDocumentSizeOverlay';
|
|
||||||
import { CanvasInpaintMask } from './CanvasInpaintMask';
|
import { CanvasInpaintMask } from './CanvasInpaintMask';
|
||||||
import { CanvasLayer } from './CanvasLayer';
|
import { CanvasLayer } from './CanvasLayer';
|
||||||
import { CanvasPreview } from './CanvasPreview';
|
import { CanvasPreview } from './CanvasPreview';
|
||||||
@ -92,7 +91,6 @@ export class CanvasManager {
|
|||||||
this.preview = new CanvasPreview(
|
this.preview = new CanvasPreview(
|
||||||
new CanvasBbox(this),
|
new CanvasBbox(this),
|
||||||
new CanvasTool(this),
|
new CanvasTool(this),
|
||||||
new CanvasDocumentSizeOverlay(this),
|
|
||||||
new CanvasStagingArea(this),
|
new CanvasStagingArea(this),
|
||||||
new CanvasProgressPreview(this)
|
new CanvasProgressPreview(this)
|
||||||
);
|
);
|
||||||
@ -221,7 +219,6 @@ export class CanvasManager {
|
|||||||
scale: this.stage.scaleX(),
|
scale: this.stage.scaleX(),
|
||||||
});
|
});
|
||||||
this.background.render();
|
this.background.render();
|
||||||
this.preview.documentSizeOverlay.render();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render = async () => {
|
render = async () => {
|
||||||
@ -245,7 +242,7 @@ export class CanvasManager {
|
|||||||
if (
|
if (
|
||||||
this.isFirstRender ||
|
this.isFirstRender ||
|
||||||
state.initialImage !== this.prevState.initialImage ||
|
state.initialImage !== this.prevState.initialImage ||
|
||||||
state.document !== this.prevState.document ||
|
state.bbox.rect !== this.prevState.bbox.rect ||
|
||||||
state.tool.selected !== this.prevState.tool.selected ||
|
state.tool.selected !== this.prevState.tool.selected ||
|
||||||
state.selectedEntityIdentifier?.id !== this.prevState.selectedEntityIdentifier?.id
|
state.selectedEntityIdentifier?.id !== this.prevState.selectedEntityIdentifier?.id
|
||||||
) {
|
) {
|
||||||
@ -285,11 +282,6 @@ export class CanvasManager {
|
|||||||
await this.renderControlAdapters();
|
await this.renderControlAdapters();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isFirstRender || state.document !== this.prevState.document) {
|
|
||||||
log.debug('Rendering document bounds overlay');
|
|
||||||
await this.preview.documentSizeOverlay.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
this.isFirstRender ||
|
this.isFirstRender ||
|
||||||
state.bbox !== this.prevState.bbox ||
|
state.bbox !== this.prevState.bbox ||
|
||||||
@ -367,9 +359,6 @@ export class CanvasManager {
|
|||||||
});
|
});
|
||||||
|
|
||||||
log.debug('First render of konva stage');
|
log.debug('First render of konva stage');
|
||||||
// On first render, the document should be fit to the stage.
|
|
||||||
this.preview.documentSizeOverlay.render();
|
|
||||||
this.preview.documentSizeOverlay.fitToStage();
|
|
||||||
this.preview.tool.render();
|
this.preview.tool.render();
|
||||||
this.render();
|
this.render();
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ import type { CanvasProgressPreview } from 'features/controlLayers/konva/CanvasP
|
|||||||
import Konva from 'konva';
|
import Konva from 'konva';
|
||||||
|
|
||||||
import type { CanvasBbox } from './CanvasBbox';
|
import type { CanvasBbox } from './CanvasBbox';
|
||||||
import type { CanvasDocumentSizeOverlay } from './CanvasDocumentSizeOverlay';
|
|
||||||
import type { CanvasStagingArea } from './CanvasStagingArea';
|
import type { CanvasStagingArea } from './CanvasStagingArea';
|
||||||
import type { CanvasTool } from './CanvasTool';
|
import type { CanvasTool } from './CanvasTool';
|
||||||
|
|
||||||
@ -10,22 +9,17 @@ export class CanvasPreview {
|
|||||||
layer: Konva.Layer;
|
layer: Konva.Layer;
|
||||||
tool: CanvasTool;
|
tool: CanvasTool;
|
||||||
bbox: CanvasBbox;
|
bbox: CanvasBbox;
|
||||||
documentSizeOverlay: CanvasDocumentSizeOverlay;
|
|
||||||
stagingArea: CanvasStagingArea;
|
stagingArea: CanvasStagingArea;
|
||||||
progressPreview: CanvasProgressPreview;
|
progressPreview: CanvasProgressPreview;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
bbox: CanvasBbox,
|
bbox: CanvasBbox,
|
||||||
tool: CanvasTool,
|
tool: CanvasTool,
|
||||||
documentSizeOverlay: CanvasDocumentSizeOverlay,
|
|
||||||
stagingArea: CanvasStagingArea,
|
stagingArea: CanvasStagingArea,
|
||||||
progressPreview: CanvasProgressPreview
|
progressPreview: CanvasProgressPreview
|
||||||
) {
|
) {
|
||||||
this.layer = new Konva.Layer({ listening: true, imageSmoothingEnabled: false });
|
this.layer = new Konva.Layer({ listening: true, imageSmoothingEnabled: false });
|
||||||
|
|
||||||
this.documentSizeOverlay = documentSizeOverlay;
|
|
||||||
this.layer.add(this.documentSizeOverlay.group);
|
|
||||||
|
|
||||||
this.stagingArea = stagingArea;
|
this.stagingArea = stagingArea;
|
||||||
this.layer.add(this.stagingArea.group);
|
this.layer.add(this.stagingArea.group);
|
||||||
|
|
||||||
|
@ -207,9 +207,6 @@ export class CanvasStateApi {
|
|||||||
getBbox = () => {
|
getBbox = () => {
|
||||||
return this.getState().bbox;
|
return this.getState().bbox;
|
||||||
};
|
};
|
||||||
getDocument = () => {
|
|
||||||
return this.getState().document;
|
|
||||||
};
|
|
||||||
getToolState = () => {
|
getToolState = () => {
|
||||||
return this.getState().tool;
|
return this.getState().tool;
|
||||||
};
|
};
|
||||||
|
@ -137,14 +137,14 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
|
|||||||
|
|
||||||
function getClip(entity: RegionEntity | LayerEntity | InpaintMaskEntity) {
|
function getClip(entity: RegionEntity | LayerEntity | InpaintMaskEntity) {
|
||||||
const settings = getSettings();
|
const settings = getSettings();
|
||||||
const bbox = getBbox();
|
const bboxRect = getBbox().rect;
|
||||||
|
|
||||||
if (settings.clipToBbox) {
|
if (settings.clipToBbox) {
|
||||||
return {
|
return {
|
||||||
x: bbox.x - entity.x,
|
x: bboxRect.x - entity.x,
|
||||||
y: bbox.y - entity.y,
|
y: bboxRect.y - entity.y,
|
||||||
width: bbox.width,
|
width: bboxRect.width,
|
||||||
height: bbox.height,
|
height: bboxRect.height,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
@ -486,7 +486,6 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
|
|||||||
stage.position(newPos);
|
stage.position(newPos);
|
||||||
setStageAttrs({ ...newPos, width: stage.width(), height: stage.height(), scale: newScale });
|
setStageAttrs({ ...newPos, width: stage.width(), height: stage.height(), scale: newScale });
|
||||||
manager.background.render();
|
manager.background.render();
|
||||||
manager.preview.documentSizeOverlay.render();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
manager.preview.tool.render();
|
manager.preview.tool.render();
|
||||||
@ -502,7 +501,6 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
|
|||||||
scale: stage.scaleX(),
|
scale: stage.scaleX(),
|
||||||
});
|
});
|
||||||
manager.background.render();
|
manager.background.render();
|
||||||
manager.preview.documentSizeOverlay.render();
|
|
||||||
manager.preview.tool.render();
|
manager.preview.tool.render();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -540,9 +538,8 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
|
|||||||
} else if (e.key === 'r') {
|
} else if (e.key === 'r') {
|
||||||
setLastCursorPos(null);
|
setLastCursorPos(null);
|
||||||
setLastMouseDownPos(null);
|
setLastMouseDownPos(null);
|
||||||
manager.preview.documentSizeOverlay.fitToStage();
|
|
||||||
manager.background.render();
|
manager.background.render();
|
||||||
manager.preview.documentSizeOverlay.render();
|
// TODO(psyche): restore some kind of fit
|
||||||
}
|
}
|
||||||
manager.preview.tool.render();
|
manager.preview.tool.render();
|
||||||
};
|
};
|
||||||
|
@ -1,12 +1,17 @@
|
|||||||
import type { PayloadAction, SliceCaseReducers } from '@reduxjs/toolkit';
|
import type { PayloadAction, SliceCaseReducers } from '@reduxjs/toolkit';
|
||||||
|
import { deepClone } from 'common/util/deepClone';
|
||||||
|
import { roundDownToMultiple, roundToMultiple } from 'common/util/roundDownToMultiple';
|
||||||
import type { BoundingBoxScaleMethod, CanvasV2State, Size } from 'features/controlLayers/store/types';
|
import type { BoundingBoxScaleMethod, CanvasV2State, Size } from 'features/controlLayers/store/types';
|
||||||
import { getScaledBoundingBoxDimensions } from 'features/controlLayers/util/getScaledBoundingBoxDimensions';
|
import { getScaledBoundingBoxDimensions } from 'features/controlLayers/util/getScaledBoundingBoxDimensions';
|
||||||
|
import { calculateNewSize } from 'features/parameters/components/DocumentSize/calculateNewSize';
|
||||||
|
import { ASPECT_RATIO_MAP, initialAspectRatioState } from 'features/parameters/components/DocumentSize/constants';
|
||||||
|
import type { AspectRatioID } from 'features/parameters/components/DocumentSize/types';
|
||||||
import { getOptimalDimension } from 'features/parameters/util/optimalDimension';
|
import { getOptimalDimension } from 'features/parameters/util/optimalDimension';
|
||||||
import type { IRect } from 'konva/lib/types';
|
import type { IRect } from 'konva/lib/types';
|
||||||
import { pick } from 'lodash-es';
|
import { pick } from 'lodash-es';
|
||||||
|
|
||||||
export const bboxReducers = {
|
export const bboxReducers = {
|
||||||
scaledBboxChanged: (state, action: PayloadAction<Partial<Size>>) => {
|
bboxScaledSizeChanged: (state, action: PayloadAction<Partial<Size>>) => {
|
||||||
state.layers.imageCache = null;
|
state.layers.imageCache = null;
|
||||||
state.bbox.scaledSize = { ...state.bbox.scaledSize, ...action.payload };
|
state.bbox.scaledSize = { ...state.bbox.scaledSize, ...action.payload };
|
||||||
},
|
},
|
||||||
@ -30,4 +35,116 @@ export const bboxReducers = {
|
|||||||
state.bbox.scaledSize = getScaledBoundingBoxDimensions(size, optimalDimension);
|
state.bbox.scaledSize = getScaledBoundingBoxDimensions(size, optimalDimension);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
bboxWidthChanged: (state, action: PayloadAction<{ width: number; updateAspectRatio?: boolean; clamp?: boolean }>) => {
|
||||||
|
const { width, updateAspectRatio, clamp } = action.payload;
|
||||||
|
state.bbox.rect.width = clamp ? Math.max(roundDownToMultiple(width, 8), 64) : width;
|
||||||
|
|
||||||
|
if (state.bbox.aspectRatio.isLocked) {
|
||||||
|
state.bbox.rect.height = roundToMultiple(state.bbox.rect.width / state.bbox.aspectRatio.value, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateAspectRatio || !state.bbox.aspectRatio.isLocked) {
|
||||||
|
state.bbox.aspectRatio.value = state.bbox.rect.width / state.bbox.rect.height;
|
||||||
|
state.bbox.aspectRatio.id = 'Free';
|
||||||
|
state.bbox.aspectRatio.isLocked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!state.session.isActive) {
|
||||||
|
if (state.initialImage.imageObject) {
|
||||||
|
state.initialImage.imageObject.width = state.bbox.rect.width;
|
||||||
|
state.initialImage.imageObject.height = state.bbox.rect.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
bboxHeightChanged: (
|
||||||
|
state,
|
||||||
|
action: PayloadAction<{ height: number; updateAspectRatio?: boolean; clamp?: boolean }>
|
||||||
|
) => {
|
||||||
|
const { height, updateAspectRatio, clamp } = action.payload;
|
||||||
|
|
||||||
|
state.bbox.rect.height = clamp ? Math.max(roundDownToMultiple(height, 8), 64) : height;
|
||||||
|
|
||||||
|
if (state.bbox.aspectRatio.isLocked) {
|
||||||
|
state.bbox.rect.width = roundToMultiple(state.bbox.rect.height * state.bbox.aspectRatio.value, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateAspectRatio || !state.bbox.aspectRatio.isLocked) {
|
||||||
|
state.bbox.aspectRatio.value = state.bbox.rect.width / state.bbox.rect.height;
|
||||||
|
state.bbox.aspectRatio.id = 'Free';
|
||||||
|
state.bbox.aspectRatio.isLocked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!state.session.isActive) {
|
||||||
|
if (state.initialImage.imageObject) {
|
||||||
|
state.initialImage.imageObject.width = state.bbox.rect.width;
|
||||||
|
state.initialImage.imageObject.height = state.bbox.rect.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
bboxAspectRatioLockToggled: (state) => {
|
||||||
|
state.bbox.aspectRatio.isLocked = !state.bbox.aspectRatio.isLocked;
|
||||||
|
},
|
||||||
|
bboxAspectRatioIdChanged: (state, action: PayloadAction<{ id: AspectRatioID }>) => {
|
||||||
|
const { id } = action.payload;
|
||||||
|
state.bbox.aspectRatio.id = id;
|
||||||
|
if (id === 'Free') {
|
||||||
|
state.bbox.aspectRatio.isLocked = false;
|
||||||
|
} else {
|
||||||
|
state.bbox.aspectRatio.isLocked = true;
|
||||||
|
state.bbox.aspectRatio.value = ASPECT_RATIO_MAP[id].ratio;
|
||||||
|
const { width, height } = calculateNewSize(
|
||||||
|
state.bbox.aspectRatio.value,
|
||||||
|
state.bbox.rect.width * state.bbox.rect.height
|
||||||
|
);
|
||||||
|
state.bbox.rect.width = width;
|
||||||
|
state.bbox.rect.height = height;
|
||||||
|
}
|
||||||
|
if (!state.session.isActive) {
|
||||||
|
if (state.initialImage.imageObject) {
|
||||||
|
state.initialImage.imageObject.width = state.bbox.rect.width;
|
||||||
|
state.initialImage.imageObject.height = state.bbox.rect.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
bboxDimensionsSwapped: (state) => {
|
||||||
|
state.bbox.aspectRatio.value = 1 / state.bbox.aspectRatio.value;
|
||||||
|
if (state.bbox.aspectRatio.id === 'Free') {
|
||||||
|
const newWidth = state.bbox.rect.height;
|
||||||
|
const newHeight = state.bbox.rect.width;
|
||||||
|
state.bbox.rect.width = newWidth;
|
||||||
|
state.bbox.rect.height = newHeight;
|
||||||
|
} else {
|
||||||
|
const { width, height } = calculateNewSize(
|
||||||
|
state.bbox.aspectRatio.value,
|
||||||
|
state.bbox.rect.width * state.bbox.rect.height
|
||||||
|
);
|
||||||
|
state.bbox.rect.width = width;
|
||||||
|
state.bbox.rect.height = height;
|
||||||
|
state.bbox.aspectRatio.id = ASPECT_RATIO_MAP[state.bbox.aspectRatio.id].inverseID;
|
||||||
|
}
|
||||||
|
if (!state.session.isActive) {
|
||||||
|
if (state.initialImage.imageObject) {
|
||||||
|
state.initialImage.imageObject.width = state.bbox.rect.width;
|
||||||
|
state.initialImage.imageObject.height = state.bbox.rect.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
bboxSizeOptimized: (state) => {
|
||||||
|
const optimalDimension = getOptimalDimension(state.params.model);
|
||||||
|
if (state.bbox.aspectRatio.isLocked) {
|
||||||
|
const { width, height } = calculateNewSize(state.bbox.aspectRatio.value, optimalDimension ** 2);
|
||||||
|
state.bbox.rect.width = width;
|
||||||
|
state.bbox.rect.height = height;
|
||||||
|
} else {
|
||||||
|
state.bbox.aspectRatio = deepClone(initialAspectRatioState);
|
||||||
|
state.bbox.rect.width = optimalDimension;
|
||||||
|
state.bbox.rect.height = optimalDimension;
|
||||||
|
}
|
||||||
|
if (!state.session.isActive) {
|
||||||
|
if (state.initialImage.imageObject) {
|
||||||
|
state.initialImage.imageObject.width = state.bbox.rect.width;
|
||||||
|
state.initialImage.imageObject.height = state.bbox.rect.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
} satisfies SliceCaseReducers<CanvasV2State>;
|
} satisfies SliceCaseReducers<CanvasV2State>;
|
||||||
|
@ -5,7 +5,6 @@ import { deepClone } from 'common/util/deepClone';
|
|||||||
import { bboxReducers } from 'features/controlLayers/store/bboxReducers';
|
import { bboxReducers } from 'features/controlLayers/store/bboxReducers';
|
||||||
import { compositingReducers } from 'features/controlLayers/store/compositingReducers';
|
import { compositingReducers } from 'features/controlLayers/store/compositingReducers';
|
||||||
import { controlAdaptersReducers } from 'features/controlLayers/store/controlAdaptersReducers';
|
import { controlAdaptersReducers } from 'features/controlLayers/store/controlAdaptersReducers';
|
||||||
import { documentReducers } from 'features/controlLayers/store/documentReducers';
|
|
||||||
import { initialImageReducers } from 'features/controlLayers/store/initialImageReducers';
|
import { initialImageReducers } from 'features/controlLayers/store/initialImageReducers';
|
||||||
import { inpaintMaskReducers } from 'features/controlLayers/store/inpaintMaskReducers';
|
import { inpaintMaskReducers } from 'features/controlLayers/store/inpaintMaskReducers';
|
||||||
import { ipAdaptersReducers } from 'features/controlLayers/store/ipAdaptersReducers';
|
import { ipAdaptersReducers } from 'features/controlLayers/store/ipAdaptersReducers';
|
||||||
@ -63,12 +62,9 @@ const initialState: CanvasV2State = {
|
|||||||
width: 50,
|
width: 50,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
document: {
|
|
||||||
rect: { x: 0, y: 0, width: 512, height: 512 },
|
|
||||||
aspectRatio: deepClone(initialAspectRatioState),
|
|
||||||
},
|
|
||||||
bbox: {
|
bbox: {
|
||||||
rect: { x: 0, y: 0, width: 512, height: 512 },
|
rect: { x: 0, y: 0, width: 512, height: 512 },
|
||||||
|
aspectRatio: deepClone(initialAspectRatioState),
|
||||||
scaleMethod: 'auto',
|
scaleMethod: 'auto',
|
||||||
scaledSize: {
|
scaledSize: {
|
||||||
width: 512,
|
width: 512,
|
||||||
@ -149,7 +145,6 @@ export const canvasV2Slice = createSlice({
|
|||||||
...bboxReducers,
|
...bboxReducers,
|
||||||
...inpaintMaskReducers,
|
...inpaintMaskReducers,
|
||||||
...sessionReducers,
|
...sessionReducers,
|
||||||
...documentReducers,
|
|
||||||
...initialImageReducers,
|
...initialImageReducers,
|
||||||
entitySelected: (state, action: PayloadAction<CanvasEntityIdentifier>) => {
|
entitySelected: (state, action: PayloadAction<CanvasEntityIdentifier>) => {
|
||||||
state.selectedEntityIdentifier = action.payload;
|
state.selectedEntityIdentifier = action.payload;
|
||||||
@ -164,7 +159,6 @@ export const canvasV2Slice = createSlice({
|
|||||||
canvasReset: (state) => {
|
canvasReset: (state) => {
|
||||||
state.bbox = deepClone(initialState.bbox);
|
state.bbox = deepClone(initialState.bbox);
|
||||||
state.controlAdapters = deepClone(initialState.controlAdapters);
|
state.controlAdapters = deepClone(initialState.controlAdapters);
|
||||||
state.document = deepClone(initialState.document);
|
|
||||||
state.ipAdapters = deepClone(initialState.ipAdapters);
|
state.ipAdapters = deepClone(initialState.ipAdapters);
|
||||||
state.layers = deepClone(initialState.layers);
|
state.layers = deepClone(initialState.layers);
|
||||||
state.regions = deepClone(initialState.regions);
|
state.regions = deepClone(initialState.regions);
|
||||||
@ -178,7 +172,6 @@ export const canvasV2Slice = createSlice({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const {
|
export const {
|
||||||
bboxChanged,
|
|
||||||
brushWidthChanged,
|
brushWidthChanged,
|
||||||
eraserWidthChanged,
|
eraserWidthChanged,
|
||||||
fillChanged,
|
fillChanged,
|
||||||
@ -188,17 +181,18 @@ export const {
|
|||||||
maskOpacityChanged,
|
maskOpacityChanged,
|
||||||
entitySelected,
|
entitySelected,
|
||||||
allEntitiesDeleted,
|
allEntitiesDeleted,
|
||||||
scaledBboxChanged,
|
|
||||||
bboxScaleMethodChanged,
|
|
||||||
clipToBboxChanged,
|
clipToBboxChanged,
|
||||||
canvasReset,
|
canvasReset,
|
||||||
// document
|
// bbox
|
||||||
documentWidthChanged,
|
bboxChanged,
|
||||||
documentHeightChanged,
|
bboxScaledSizeChanged,
|
||||||
documentAspectRatioLockToggled,
|
bboxScaleMethodChanged,
|
||||||
documentAspectRatioIdChanged,
|
bboxWidthChanged,
|
||||||
documentDimensionsSwapped,
|
bboxHeightChanged,
|
||||||
documentSizeOptimized,
|
bboxAspectRatioLockToggled,
|
||||||
|
bboxAspectRatioIdChanged,
|
||||||
|
bboxDimensionsSwapped,
|
||||||
|
bboxSizeOptimized,
|
||||||
// layers
|
// layers
|
||||||
layerAdded,
|
layerAdded,
|
||||||
layerRecalled,
|
layerRecalled,
|
||||||
|
@ -1,141 +0,0 @@
|
|||||||
import type { PayloadAction, SliceCaseReducers } from '@reduxjs/toolkit';
|
|
||||||
import { deepClone } from 'common/util/deepClone';
|
|
||||||
import { roundDownToMultiple, roundToMultiple } from 'common/util/roundDownToMultiple';
|
|
||||||
import type { CanvasV2State } from 'features/controlLayers/store/types';
|
|
||||||
import { calculateNewSize } from 'features/parameters/components/DocumentSize/calculateNewSize';
|
|
||||||
import { ASPECT_RATIO_MAP, initialAspectRatioState } from 'features/parameters/components/DocumentSize/constants';
|
|
||||||
import type { AspectRatioID } from 'features/parameters/components/DocumentSize/types';
|
|
||||||
import { getOptimalDimension } from 'features/parameters/util/optimalDimension';
|
|
||||||
|
|
||||||
export const documentReducers = {
|
|
||||||
documentWidthChanged: (
|
|
||||||
state,
|
|
||||||
action: PayloadAction<{ width: number; updateAspectRatio?: boolean; clamp?: boolean }>
|
|
||||||
) => {
|
|
||||||
const { width, updateAspectRatio, clamp } = action.payload;
|
|
||||||
state.document.rect.width = clamp ? Math.max(roundDownToMultiple(width, 8), 64) : width;
|
|
||||||
|
|
||||||
if (state.document.aspectRatio.isLocked) {
|
|
||||||
state.document.rect.height = roundToMultiple(state.document.rect.width / state.document.aspectRatio.value, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updateAspectRatio || !state.document.aspectRatio.isLocked) {
|
|
||||||
state.document.aspectRatio.value = state.document.rect.width / state.document.rect.height;
|
|
||||||
state.document.aspectRatio.id = 'Free';
|
|
||||||
state.document.aspectRatio.isLocked = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!state.session.isActive) {
|
|
||||||
state.bbox.rect.width = state.document.rect.width;
|
|
||||||
state.bbox.rect.height = state.document.rect.height;
|
|
||||||
|
|
||||||
if (state.initialImage.imageObject) {
|
|
||||||
state.initialImage.imageObject.width = state.document.rect.width;
|
|
||||||
state.initialImage.imageObject.height = state.document.rect.height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
documentHeightChanged: (
|
|
||||||
state,
|
|
||||||
action: PayloadAction<{ height: number; updateAspectRatio?: boolean; clamp?: boolean }>
|
|
||||||
) => {
|
|
||||||
const { height, updateAspectRatio, clamp } = action.payload;
|
|
||||||
|
|
||||||
state.document.rect.height = clamp ? Math.max(roundDownToMultiple(height, 8), 64) : height;
|
|
||||||
|
|
||||||
if (state.document.aspectRatio.isLocked) {
|
|
||||||
state.document.rect.width = roundToMultiple(state.document.rect.height * state.document.aspectRatio.value, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updateAspectRatio || !state.document.aspectRatio.isLocked) {
|
|
||||||
state.document.aspectRatio.value = state.document.rect.width / state.document.rect.height;
|
|
||||||
state.document.aspectRatio.id = 'Free';
|
|
||||||
state.document.aspectRatio.isLocked = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!state.session.isActive) {
|
|
||||||
state.bbox.rect.width = state.document.rect.width;
|
|
||||||
state.bbox.rect.height = state.document.rect.height;
|
|
||||||
|
|
||||||
if (state.initialImage.imageObject) {
|
|
||||||
state.initialImage.imageObject.width = state.document.rect.width;
|
|
||||||
state.initialImage.imageObject.height = state.document.rect.height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
documentAspectRatioLockToggled: (state) => {
|
|
||||||
state.document.aspectRatio.isLocked = !state.document.aspectRatio.isLocked;
|
|
||||||
},
|
|
||||||
documentAspectRatioIdChanged: (state, action: PayloadAction<{ id: AspectRatioID }>) => {
|
|
||||||
const { id } = action.payload;
|
|
||||||
state.document.aspectRatio.id = id;
|
|
||||||
if (id === 'Free') {
|
|
||||||
state.document.aspectRatio.isLocked = false;
|
|
||||||
} else {
|
|
||||||
state.document.aspectRatio.isLocked = true;
|
|
||||||
state.document.aspectRatio.value = ASPECT_RATIO_MAP[id].ratio;
|
|
||||||
const { width, height } = calculateNewSize(
|
|
||||||
state.document.aspectRatio.value,
|
|
||||||
state.document.rect.width * state.document.rect.height
|
|
||||||
);
|
|
||||||
state.document.rect.width = width;
|
|
||||||
state.document.rect.height = height;
|
|
||||||
}
|
|
||||||
if (!state.session.isActive) {
|
|
||||||
state.bbox.rect.width = state.document.rect.width;
|
|
||||||
state.bbox.rect.height = state.document.rect.height;
|
|
||||||
|
|
||||||
if (state.initialImage.imageObject) {
|
|
||||||
state.initialImage.imageObject.width = state.document.rect.width;
|
|
||||||
state.initialImage.imageObject.height = state.document.rect.height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
documentDimensionsSwapped: (state) => {
|
|
||||||
state.document.aspectRatio.value = 1 / state.document.aspectRatio.value;
|
|
||||||
if (state.document.aspectRatio.id === 'Free') {
|
|
||||||
const newWidth = state.document.rect.height;
|
|
||||||
const newHeight = state.document.rect.width;
|
|
||||||
state.document.rect.width = newWidth;
|
|
||||||
state.document.rect.height = newHeight;
|
|
||||||
} else {
|
|
||||||
const { width, height } = calculateNewSize(
|
|
||||||
state.document.aspectRatio.value,
|
|
||||||
state.document.rect.width * state.document.rect.height
|
|
||||||
);
|
|
||||||
state.document.rect.width = width;
|
|
||||||
state.document.rect.height = height;
|
|
||||||
state.document.aspectRatio.id = ASPECT_RATIO_MAP[state.document.aspectRatio.id].inverseID;
|
|
||||||
}
|
|
||||||
if (!state.session.isActive) {
|
|
||||||
state.bbox.rect.width = state.document.rect.width;
|
|
||||||
state.bbox.rect.height = state.document.rect.height;
|
|
||||||
|
|
||||||
if (state.initialImage.imageObject) {
|
|
||||||
state.initialImage.imageObject.width = state.document.rect.width;
|
|
||||||
state.initialImage.imageObject.height = state.document.rect.height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
documentSizeOptimized: (state) => {
|
|
||||||
const optimalDimension = getOptimalDimension(state.params.model);
|
|
||||||
if (state.document.aspectRatio.isLocked) {
|
|
||||||
const { width, height } = calculateNewSize(state.document.aspectRatio.value, optimalDimension ** 2);
|
|
||||||
state.document.rect.width = width;
|
|
||||||
state.document.rect.height = height;
|
|
||||||
} else {
|
|
||||||
state.document.aspectRatio = deepClone(initialAspectRatioState);
|
|
||||||
state.document.rect.width = optimalDimension;
|
|
||||||
state.document.rect.height = optimalDimension;
|
|
||||||
}
|
|
||||||
if (!state.session.isActive) {
|
|
||||||
state.bbox.rect.width = state.document.rect.width;
|
|
||||||
state.bbox.rect.height = state.document.rect.height;
|
|
||||||
|
|
||||||
if (state.initialImage.imageObject) {
|
|
||||||
state.initialImage.imageObject.width = state.document.rect.width;
|
|
||||||
state.initialImage.imageObject.height = state.document.rect.height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
} satisfies SliceCaseReducers<CanvasV2State>;
|
|
@ -62,8 +62,8 @@ export const paramsReducers = {
|
|||||||
// Update the bbox size to match the new model's optimal size
|
// Update the bbox size to match the new model's optimal size
|
||||||
// TODO(psyche): Should we change the document size too?
|
// TODO(psyche): Should we change the document size too?
|
||||||
const optimalDimension = getOptimalDimension(model);
|
const optimalDimension = getOptimalDimension(model);
|
||||||
if (!getIsSizeOptimal(state.document.rect.width, state.document.rect.height, optimalDimension)) {
|
if (!getIsSizeOptimal(state.bbox.rect.width, state.bbox.rect.height, optimalDimension)) {
|
||||||
const bboxDims = calculateNewSize(state.document.aspectRatio.value, optimalDimension * optimalDimension);
|
const bboxDims = calculateNewSize(state.bbox.aspectRatio.value, optimalDimension * optimalDimension);
|
||||||
state.bbox.rect.width = bboxDims.width;
|
state.bbox.rect.width = bboxDims.width;
|
||||||
state.bbox.rect.height = bboxDims.height;
|
state.bbox.rect.height = bboxDims.height;
|
||||||
|
|
||||||
|
@ -847,15 +847,6 @@ export type CanvasV2State = {
|
|||||||
eraser: { width: number };
|
eraser: { width: number };
|
||||||
fill: RgbaColor;
|
fill: RgbaColor;
|
||||||
};
|
};
|
||||||
document: {
|
|
||||||
rect: {
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
width: ParameterWidth;
|
|
||||||
height: ParameterHeight;
|
|
||||||
};
|
|
||||||
aspectRatio: AspectRatioState;
|
|
||||||
};
|
|
||||||
settings: {
|
settings: {
|
||||||
imageSmoothing: boolean;
|
imageSmoothing: boolean;
|
||||||
maskOpacity: number;
|
maskOpacity: number;
|
||||||
@ -872,6 +863,7 @@ export type CanvasV2State = {
|
|||||||
width: ParameterWidth;
|
width: ParameterWidth;
|
||||||
height: ParameterHeight;
|
height: ParameterHeight;
|
||||||
};
|
};
|
||||||
|
aspectRatio: AspectRatioState;
|
||||||
scaledSize: {
|
scaledSize: {
|
||||||
width: ParameterWidth;
|
width: ParameterWidth;
|
||||||
height: ParameterHeight;
|
height: ParameterHeight;
|
||||||
|
@ -11,9 +11,9 @@ import {
|
|||||||
getRGId,
|
getRGId,
|
||||||
} from 'features/controlLayers/konva/naming';
|
} from 'features/controlLayers/konva/naming';
|
||||||
import {
|
import {
|
||||||
|
bboxHeightChanged,
|
||||||
|
bboxWidthChanged,
|
||||||
caRecalled,
|
caRecalled,
|
||||||
documentHeightChanged,
|
|
||||||
documentWidthChanged,
|
|
||||||
ipaRecalled,
|
ipaRecalled,
|
||||||
layerAllDeleted,
|
layerAllDeleted,
|
||||||
layerRecalled,
|
layerRecalled,
|
||||||
@ -115,11 +115,11 @@ const recallScheduler: MetadataRecallFunc<ParameterScheduler> = (scheduler) => {
|
|||||||
const setSizeOptions = { updateAspectRatio: true, clamp: true };
|
const setSizeOptions = { updateAspectRatio: true, clamp: true };
|
||||||
|
|
||||||
const recallWidth: MetadataRecallFunc<ParameterWidth> = (width) => {
|
const recallWidth: MetadataRecallFunc<ParameterWidth> = (width) => {
|
||||||
getStore().dispatch(documentWidthChanged({ width, ...setSizeOptions }));
|
getStore().dispatch(bboxWidthChanged({ width, ...setSizeOptions }));
|
||||||
};
|
};
|
||||||
|
|
||||||
const recallHeight: MetadataRecallFunc<ParameterHeight> = (height) => {
|
const recallHeight: MetadataRecallFunc<ParameterHeight> = (height) => {
|
||||||
getStore().dispatch(documentHeightChanged({ height, ...setSizeOptions }));
|
getStore().dispatch(bboxHeightChanged({ height, ...setSizeOptions }));
|
||||||
};
|
};
|
||||||
|
|
||||||
const recallSteps: MetadataRecallFunc<ParameterSteps> = (steps) => {
|
const recallSteps: MetadataRecallFunc<ParameterSteps> = (steps) => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { scaledBboxChanged } from 'features/controlLayers/store/canvasV2Slice';
|
import { bboxScaledSizeChanged } from 'features/controlLayers/store/canvasV2Slice';
|
||||||
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
||||||
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 ParamScaledHeight = () => {
|
|||||||
|
|
||||||
const onChange = useCallback(
|
const onChange = useCallback(
|
||||||
(height: number) => {
|
(height: number) => {
|
||||||
dispatch(scaledBboxChanged({ height }));
|
dispatch(bboxScaledSizeChanged({ height }));
|
||||||
},
|
},
|
||||||
[dispatch]
|
[dispatch]
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { scaledBboxChanged } from 'features/controlLayers/store/canvasV2Slice';
|
import { bboxScaledSizeChanged } from 'features/controlLayers/store/canvasV2Slice';
|
||||||
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@ -19,7 +19,7 @@ const ParamScaledWidth = () => {
|
|||||||
const fineStep = useAppSelector((s) => s.config.sd.scaledBoundingBoxWidth.fineStep);
|
const fineStep = useAppSelector((s) => s.config.sd.scaledBoundingBoxWidth.fineStep);
|
||||||
const onChange = useCallback(
|
const onChange = useCallback(
|
||||||
(width: number) => {
|
(width: number) => {
|
||||||
dispatch(scaledBboxChanged({ width }));
|
dispatch(bboxScaledSizeChanged({ width }));
|
||||||
},
|
},
|
||||||
[dispatch]
|
[dispatch]
|
||||||
);
|
);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||||
import { documentHeightChanged } from 'features/controlLayers/store/canvasV2Slice';
|
import { bboxHeightChanged } from 'features/controlLayers/store/canvasV2Slice';
|
||||||
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
||||||
import { memo, useCallback, useMemo } from 'react';
|
import { memo, useCallback, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@ -10,7 +10,7 @@ export const ParamHeight = memo(() => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const optimalDimension = useAppSelector(selectOptimalDimension);
|
const optimalDimension = useAppSelector(selectOptimalDimension);
|
||||||
const height = useAppSelector((s) => s.canvasV2.document.rect.height);
|
const height = useAppSelector((s) => s.canvasV2.bbox.rect.height);
|
||||||
const sliderMin = useAppSelector((s) => s.config.sd.height.sliderMin);
|
const sliderMin = useAppSelector((s) => s.config.sd.height.sliderMin);
|
||||||
const sliderMax = useAppSelector((s) => s.config.sd.height.sliderMax);
|
const sliderMax = useAppSelector((s) => s.config.sd.height.sliderMax);
|
||||||
const numberInputMin = useAppSelector((s) => s.config.sd.height.numberInputMin);
|
const numberInputMin = useAppSelector((s) => s.config.sd.height.numberInputMin);
|
||||||
@ -20,7 +20,7 @@ export const ParamHeight = memo(() => {
|
|||||||
|
|
||||||
const onChange = useCallback(
|
const onChange = useCallback(
|
||||||
(v: number) => {
|
(v: number) => {
|
||||||
dispatch(documentHeightChanged({ height: v }));
|
dispatch(bboxHeightChanged({ height: v }));
|
||||||
},
|
},
|
||||||
[dispatch]
|
[dispatch]
|
||||||
);
|
);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||||
import { documentWidthChanged } from 'features/controlLayers/store/canvasV2Slice';
|
import { bboxWidthChanged } from 'features/controlLayers/store/canvasV2Slice';
|
||||||
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
||||||
import { memo, useCallback, useMemo } from 'react';
|
import { memo, useCallback, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@ -9,7 +9,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
export const ParamWidth = memo(() => {
|
export const ParamWidth = memo(() => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const width = useAppSelector((s) => s.canvasV2.document.rect.width);
|
const width = useAppSelector((s) => s.canvasV2.bbox.rect.width);
|
||||||
const optimalDimension = useAppSelector(selectOptimalDimension);
|
const optimalDimension = useAppSelector(selectOptimalDimension);
|
||||||
const sliderMin = useAppSelector((s) => s.config.sd.width.sliderMin);
|
const sliderMin = useAppSelector((s) => s.config.sd.width.sliderMin);
|
||||||
const sliderMax = useAppSelector((s) => s.config.sd.width.sliderMax);
|
const sliderMax = useAppSelector((s) => s.config.sd.width.sliderMax);
|
||||||
@ -20,7 +20,7 @@ export const ParamWidth = memo(() => {
|
|||||||
|
|
||||||
const onChange = useCallback(
|
const onChange = useCallback(
|
||||||
(v: number) => {
|
(v: number) => {
|
||||||
dispatch(documentWidthChanged({ width: v }));
|
dispatch(bboxWidthChanged({ width: v }));
|
||||||
},
|
},
|
||||||
[dispatch]
|
[dispatch]
|
||||||
);
|
);
|
||||||
|
@ -16,13 +16,13 @@ import {
|
|||||||
} from './constants';
|
} from './constants';
|
||||||
|
|
||||||
export const AspectRatioIconPreview = memo(() => {
|
export const AspectRatioIconPreview = memo(() => {
|
||||||
const document = useAppSelector((s) => s.canvasV2.document);
|
const bbox = useAppSelector((s) => s.canvasV2.bbox);
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
const containerSize = useSize(containerRef);
|
const containerSize = useSize(containerRef);
|
||||||
|
|
||||||
const shouldShowIcon = useMemo(
|
const shouldShowIcon = useMemo(
|
||||||
() => document.aspectRatio.value < ICON_HIGH_CUTOFF && document.aspectRatio.value > ICON_LOW_CUTOFF,
|
() => bbox.aspectRatio.value < ICON_HIGH_CUTOFF && bbox.aspectRatio.value > ICON_LOW_CUTOFF,
|
||||||
[document.aspectRatio.value]
|
[bbox.aspectRatio.value]
|
||||||
);
|
);
|
||||||
|
|
||||||
const { width, height } = useMemo(() => {
|
const { width, height } = useMemo(() => {
|
||||||
@ -30,19 +30,19 @@ export const AspectRatioIconPreview = memo(() => {
|
|||||||
return { width: 0, height: 0 };
|
return { width: 0, height: 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
let width = document.rect.width;
|
let width = bbox.rect.width;
|
||||||
let height = document.rect.height;
|
let height = bbox.rect.height;
|
||||||
|
|
||||||
if (document.rect.width > document.rect.height) {
|
if (bbox.rect.width > bbox.rect.height) {
|
||||||
width = containerSize.width;
|
width = containerSize.width;
|
||||||
height = width / document.aspectRatio.value;
|
height = width / bbox.aspectRatio.value;
|
||||||
} else {
|
} else {
|
||||||
height = containerSize.height;
|
height = containerSize.height;
|
||||||
width = height * document.aspectRatio.value;
|
width = height * bbox.aspectRatio.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return { width, height };
|
return { width, height };
|
||||||
}, [containerSize, document.rect.width, document.rect.height, document.aspectRatio.value]);
|
}, [containerSize, bbox.rect.width, bbox.rect.height, bbox.aspectRatio.value]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex w="full" h="full" alignItems="center" justifyContent="center" ref={containerRef}>
|
<Flex w="full" h="full" alignItems="center" justifyContent="center" ref={containerRef}>
|
||||||
|
@ -3,7 +3,7 @@ import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
|||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import type { SingleValue } from 'chakra-react-select';
|
import type { SingleValue } from 'chakra-react-select';
|
||||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||||
import { documentAspectRatioIdChanged } from 'features/controlLayers/store/canvasV2Slice';
|
import { bboxAspectRatioIdChanged } from 'features/controlLayers/store/canvasV2Slice';
|
||||||
import { ASPECT_RATIO_OPTIONS } from 'features/parameters/components/DocumentSize/constants';
|
import { ASPECT_RATIO_OPTIONS } from 'features/parameters/components/DocumentSize/constants';
|
||||||
import { isAspectRatioID } from 'features/parameters/components/DocumentSize/types';
|
import { isAspectRatioID } from 'features/parameters/components/DocumentSize/types';
|
||||||
import { memo, useCallback, useMemo } from 'react';
|
import { memo, useCallback, useMemo } from 'react';
|
||||||
@ -12,14 +12,14 @@ import { useTranslation } from 'react-i18next';
|
|||||||
export const AspectRatioSelect = memo(() => {
|
export const AspectRatioSelect = memo(() => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const id = useAppSelector((s) => s.canvasV2.document.aspectRatio.id);
|
const id = useAppSelector((s) => s.canvasV2.bbox.aspectRatio.id);
|
||||||
|
|
||||||
const onChange = useCallback(
|
const onChange = useCallback(
|
||||||
(v: SingleValue<ComboboxOption>) => {
|
(v: SingleValue<ComboboxOption>) => {
|
||||||
if (!v || !isAspectRatioID(v.value)) {
|
if (!v || !isAspectRatioID(v.value)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatch(documentAspectRatioIdChanged({ id: v.value }));
|
dispatch(bboxAspectRatioIdChanged({ id: v.value }));
|
||||||
},
|
},
|
||||||
[dispatch]
|
[dispatch]
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { IconButton } from '@invoke-ai/ui-library';
|
import { IconButton } from '@invoke-ai/ui-library';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { documentAspectRatioLockToggled } from 'features/controlLayers/store/canvasV2Slice';
|
import { bboxAspectRatioLockToggled } from 'features/controlLayers/store/canvasV2Slice';
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { PiLockSimpleFill, PiLockSimpleOpenBold } from 'react-icons/pi';
|
import { PiLockSimpleFill, PiLockSimpleOpenBold } from 'react-icons/pi';
|
||||||
@ -8,9 +8,9 @@ import { PiLockSimpleFill, PiLockSimpleOpenBold } from 'react-icons/pi';
|
|||||||
export const LockAspectRatioButton = memo(() => {
|
export const LockAspectRatioButton = memo(() => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const isLocked = useAppSelector((s) => s.canvasV2.document.aspectRatio.isLocked);
|
const isLocked = useAppSelector((s) => s.canvasV2.bbox.aspectRatio.isLocked);
|
||||||
const onClick = useCallback(() => {
|
const onClick = useCallback(() => {
|
||||||
dispatch(documentAspectRatioLockToggled());
|
dispatch(bboxAspectRatioLockToggled());
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { IconButton } from '@invoke-ai/ui-library';
|
import { IconButton } from '@invoke-ai/ui-library';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { documentSizeOptimized } from 'features/controlLayers/store/canvasV2Slice';
|
import { bboxSizeOptimized } from 'features/controlLayers/store/canvasV2Slice';
|
||||||
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
||||||
import { getIsSizeTooLarge, getIsSizeTooSmall } from 'features/parameters/util/optimalDimension';
|
import { getIsSizeTooLarge, getIsSizeTooSmall } from 'features/parameters/util/optimalDimension';
|
||||||
import { memo, useCallback, useMemo } from 'react';
|
import { memo, useCallback, useMemo } from 'react';
|
||||||
@ -10,8 +10,8 @@ import { RiSparklingFill } from 'react-icons/ri';
|
|||||||
export const SetOptimalSizeButton = memo(() => {
|
export const SetOptimalSizeButton = memo(() => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const width = useAppSelector((s) => s.canvasV2.document.rect.width);
|
const width = useAppSelector((s) => s.canvasV2.bbox.rect.width);
|
||||||
const height = useAppSelector((s) => s.canvasV2.document.rect.height);
|
const height = useAppSelector((s) => s.canvasV2.bbox.rect.height);
|
||||||
const optimalDimension = useAppSelector(selectOptimalDimension);
|
const optimalDimension = useAppSelector(selectOptimalDimension);
|
||||||
const isSizeTooSmall = useMemo(
|
const isSizeTooSmall = useMemo(
|
||||||
() => getIsSizeTooSmall(width, height, optimalDimension),
|
() => getIsSizeTooSmall(width, height, optimalDimension),
|
||||||
@ -22,7 +22,7 @@ export const SetOptimalSizeButton = memo(() => {
|
|||||||
[height, width, optimalDimension]
|
[height, width, optimalDimension]
|
||||||
);
|
);
|
||||||
const onClick = useCallback(() => {
|
const onClick = useCallback(() => {
|
||||||
dispatch(documentSizeOptimized());
|
dispatch(bboxSizeOptimized());
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
const tooltip = useMemo(() => {
|
const tooltip = useMemo(() => {
|
||||||
if (isSizeTooSmall) {
|
if (isSizeTooSmall) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { IconButton } from '@invoke-ai/ui-library';
|
import { IconButton } from '@invoke-ai/ui-library';
|
||||||
import { useAppDispatch } from 'app/store/storeHooks';
|
import { useAppDispatch } from 'app/store/storeHooks';
|
||||||
import { documentDimensionsSwapped } from 'features/controlLayers/store/canvasV2Slice';
|
import { bboxDimensionsSwapped } from 'features/controlLayers/store/canvasV2Slice';
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { PiArrowsDownUpBold } from 'react-icons/pi';
|
import { PiArrowsDownUpBold } from 'react-icons/pi';
|
||||||
@ -9,7 +9,7 @@ export const SwapDimensionsButton = memo(() => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const onClick = useCallback(() => {
|
const onClick = useCallback(() => {
|
||||||
dispatch(documentDimensionsSwapped());
|
dispatch(bboxDimensionsSwapped());
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
return (
|
return (
|
||||||
<IconButton
|
<IconButton
|
||||||
|
@ -24,8 +24,8 @@ const selector = createMemoizedSelector([selectHrfSlice, selectCanvasV2Slice], (
|
|||||||
const badges: string[] = [];
|
const badges: string[] = [];
|
||||||
const isSDXL = model?.base === 'sdxl';
|
const isSDXL = model?.base === 'sdxl';
|
||||||
|
|
||||||
const { aspectRatio } = canvasV2.document;
|
const { aspectRatio } = canvasV2.bbox;
|
||||||
const { width, height } = canvasV2.document.rect;
|
const { width, height } = canvasV2.bbox.rect;
|
||||||
|
|
||||||
badges.push(`${width}×${height}`);
|
badges.push(`${width}×${height}`);
|
||||||
badges.push(aspectRatio.id);
|
badges.push(aspectRatio.id);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user