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 { JSONObject } from 'common/types';
|
||||
import {
|
||||
bboxHeightChanged,
|
||||
bboxWidthChanged,
|
||||
caModelChanged,
|
||||
documentHeightChanged,
|
||||
documentWidthChanged,
|
||||
ipaModelChanged,
|
||||
loraDeleted,
|
||||
modelChanged,
|
||||
@ -83,16 +83,16 @@ const handleMainModels: ModelHandler = (models, state, dispatch, log) => {
|
||||
dispatch(modelChanged({ model: defaultModelInList, previousModel: currentModel }));
|
||||
|
||||
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;
|
||||
}
|
||||
const { width, height } = calculateNewSize(
|
||||
state.canvasV2.document.aspectRatio.value,
|
||||
state.canvasV2.bbox.aspectRatio.value,
|
||||
optimalDimension * optimalDimension
|
||||
);
|
||||
|
||||
dispatch(documentWidthChanged({ width }));
|
||||
dispatch(documentHeightChanged({ height }));
|
||||
dispatch(bboxWidthChanged({ width }));
|
||||
dispatch(bboxHeightChanged({ height }));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import type { AppStartListening } from 'app/store/middleware/listenerMiddleware';
|
||||
import {
|
||||
documentHeightChanged,
|
||||
documentWidthChanged,
|
||||
bboxHeightChanged,
|
||||
bboxWidthChanged,
|
||||
setCfgRescaleMultiplier,
|
||||
setCfgScale,
|
||||
setScheduler,
|
||||
@ -99,13 +99,13 @@ export const addSetDefaultSettingsListener = (startAppListening: AppStartListeni
|
||||
const setSizeOptions = { updateAspectRatio: true, clamp: true };
|
||||
if (width) {
|
||||
if (isParameterWidth(width)) {
|
||||
dispatch(documentWidthChanged({ width, ...setSizeOptions }));
|
||||
dispatch(bboxWidthChanged({ width, ...setSizeOptions }));
|
||||
}
|
||||
}
|
||||
|
||||
if (height) {
|
||||
if (isParameterHeight(height)) {
|
||||
dispatch(documentHeightChanged({ height, ...setSizeOptions }));
|
||||
dispatch(bboxHeightChanged({ height, ...setSizeOptions }));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ type ResizeDirection =
|
||||
| 'down-right';
|
||||
|
||||
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 setDirUpLeft = useCallback(() => {
|
||||
|
@ -3,7 +3,7 @@ import { skipToken } from '@reduxjs/toolkit/query';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import IAIDndImage from 'common/components/IAIDndImage';
|
||||
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 type { ControlAdapterEntity } from 'features/controlLayers/store/types';
|
||||
import type { ImageDraggableData, TypesafeDroppableData } from 'features/dnd/types';
|
||||
@ -89,15 +89,15 @@ export const CAImagePreview = memo(
|
||||
|
||||
if (shift) {
|
||||
const { width, height } = controlImage;
|
||||
dispatch(documentWidthChanged({ width, ...options }));
|
||||
dispatch(documentHeightChanged({ height, ...options }));
|
||||
dispatch(bboxWidthChanged({ width, ...options }));
|
||||
dispatch(bboxHeightChanged({ height, ...options }));
|
||||
} else {
|
||||
const { width, height } = calculateNewSize(
|
||||
controlImage.width / controlImage.height,
|
||||
optimalDimension * optimalDimension
|
||||
);
|
||||
dispatch(documentWidthChanged({ width, ...options }));
|
||||
dispatch(documentHeightChanged({ height, ...options }));
|
||||
dispatch(bboxWidthChanged({ width, ...options }));
|
||||
dispatch(bboxHeightChanged({ height, ...options }));
|
||||
}
|
||||
}, [controlImage, dispatch, optimalDimension, shift]);
|
||||
|
||||
|
@ -20,12 +20,10 @@ export const HeadsUpDisplay = memo(() => {
|
||||
const lastMouseDownPos = useStore($lastMouseDownPos);
|
||||
const lastAddedPoint = useStore($lastAddedPoint);
|
||||
const bbox = useAppSelector((s) => s.canvasV2.bbox);
|
||||
const document = useAppSelector((s) => s.canvasV2.document);
|
||||
|
||||
return (
|
||||
<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="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 Size"
|
||||
|
@ -3,7 +3,7 @@ import { skipToken } from '@reduxjs/toolkit/query';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import IAIDndImage from 'common/components/IAIDndImage';
|
||||
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 type { ImageWithDims } from 'features/controlLayers/store/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 };
|
||||
if (shift) {
|
||||
const { width, height } = controlImage;
|
||||
dispatch(documentWidthChanged({ width, ...options }));
|
||||
dispatch(documentHeightChanged({ height, ...options }));
|
||||
dispatch(bboxWidthChanged({ width, ...options }));
|
||||
dispatch(bboxHeightChanged({ height, ...options }));
|
||||
} else {
|
||||
const { width, height } = calculateNewSize(
|
||||
controlImage.width / controlImage.height,
|
||||
optimalDimension * optimalDimension
|
||||
);
|
||||
dispatch(documentWidthChanged({ width, ...options }));
|
||||
dispatch(documentHeightChanged({ height, ...options }));
|
||||
dispatch(bboxWidthChanged({ width, ...options }));
|
||||
dispatch(bboxHeightChanged({ height, ...options }));
|
||||
}
|
||||
}, [controlImage, dispatch, optimalDimension, shift]);
|
||||
|
||||
|
@ -3,7 +3,7 @@ import { skipToken } from '@reduxjs/toolkit/query';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import IAIDndImage from 'common/components/IAIDndImage';
|
||||
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 type { ImageDraggableData, InitialImageDropData } from 'features/dnd/types';
|
||||
import { calculateNewSize } from 'features/parameters/components/DocumentSize/calculateNewSize';
|
||||
@ -36,12 +36,12 @@ export const InitialImagePreview = memo(() => {
|
||||
const options = { updateAspectRatio: true, clamp: true };
|
||||
if (shift) {
|
||||
const { width, height } = imageDTO;
|
||||
dispatch(documentWidthChanged({ width, ...options }));
|
||||
dispatch(documentHeightChanged({ height, ...options }));
|
||||
dispatch(bboxWidthChanged({ width, ...options }));
|
||||
dispatch(bboxHeightChanged({ height, ...options }));
|
||||
} else {
|
||||
const { width, height } = calculateNewSize(imageDTO.width / imageDTO.height, optimalDimension * optimalDimension);
|
||||
dispatch(documentWidthChanged({ width, ...options }));
|
||||
dispatch(documentHeightChanged({ height, ...options }));
|
||||
dispatch(bboxWidthChanged({ width, ...options }));
|
||||
dispatch(bboxHeightChanged({ height, ...options }));
|
||||
}
|
||||
}, [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 { CanvasBbox } from './CanvasBbox';
|
||||
import { CanvasControlAdapter } from './CanvasControlAdapter';
|
||||
import { CanvasDocumentSizeOverlay } from './CanvasDocumentSizeOverlay';
|
||||
import { CanvasInpaintMask } from './CanvasInpaintMask';
|
||||
import { CanvasLayer } from './CanvasLayer';
|
||||
import { CanvasPreview } from './CanvasPreview';
|
||||
@ -92,7 +91,6 @@ export class CanvasManager {
|
||||
this.preview = new CanvasPreview(
|
||||
new CanvasBbox(this),
|
||||
new CanvasTool(this),
|
||||
new CanvasDocumentSizeOverlay(this),
|
||||
new CanvasStagingArea(this),
|
||||
new CanvasProgressPreview(this)
|
||||
);
|
||||
@ -221,7 +219,6 @@ export class CanvasManager {
|
||||
scale: this.stage.scaleX(),
|
||||
});
|
||||
this.background.render();
|
||||
this.preview.documentSizeOverlay.render();
|
||||
}
|
||||
|
||||
render = async () => {
|
||||
@ -245,7 +242,7 @@ export class CanvasManager {
|
||||
if (
|
||||
this.isFirstRender ||
|
||||
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.selectedEntityIdentifier?.id !== this.prevState.selectedEntityIdentifier?.id
|
||||
) {
|
||||
@ -285,11 +282,6 @@ export class CanvasManager {
|
||||
await this.renderControlAdapters();
|
||||
}
|
||||
|
||||
if (this.isFirstRender || state.document !== this.prevState.document) {
|
||||
log.debug('Rendering document bounds overlay');
|
||||
await this.preview.documentSizeOverlay.render();
|
||||
}
|
||||
|
||||
if (
|
||||
this.isFirstRender ||
|
||||
state.bbox !== this.prevState.bbox ||
|
||||
@ -367,9 +359,6 @@ export class CanvasManager {
|
||||
});
|
||||
|
||||
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.render();
|
||||
|
||||
|
@ -2,7 +2,6 @@ import type { CanvasProgressPreview } from 'features/controlLayers/konva/CanvasP
|
||||
import Konva from 'konva';
|
||||
|
||||
import type { CanvasBbox } from './CanvasBbox';
|
||||
import type { CanvasDocumentSizeOverlay } from './CanvasDocumentSizeOverlay';
|
||||
import type { CanvasStagingArea } from './CanvasStagingArea';
|
||||
import type { CanvasTool } from './CanvasTool';
|
||||
|
||||
@ -10,22 +9,17 @@ export class CanvasPreview {
|
||||
layer: Konva.Layer;
|
||||
tool: CanvasTool;
|
||||
bbox: CanvasBbox;
|
||||
documentSizeOverlay: CanvasDocumentSizeOverlay;
|
||||
stagingArea: CanvasStagingArea;
|
||||
progressPreview: CanvasProgressPreview;
|
||||
|
||||
constructor(
|
||||
bbox: CanvasBbox,
|
||||
tool: CanvasTool,
|
||||
documentSizeOverlay: CanvasDocumentSizeOverlay,
|
||||
stagingArea: CanvasStagingArea,
|
||||
progressPreview: CanvasProgressPreview
|
||||
) {
|
||||
this.layer = new Konva.Layer({ listening: true, imageSmoothingEnabled: false });
|
||||
|
||||
this.documentSizeOverlay = documentSizeOverlay;
|
||||
this.layer.add(this.documentSizeOverlay.group);
|
||||
|
||||
this.stagingArea = stagingArea;
|
||||
this.layer.add(this.stagingArea.group);
|
||||
|
||||
|
@ -207,9 +207,6 @@ export class CanvasStateApi {
|
||||
getBbox = () => {
|
||||
return this.getState().bbox;
|
||||
};
|
||||
getDocument = () => {
|
||||
return this.getState().document;
|
||||
};
|
||||
getToolState = () => {
|
||||
return this.getState().tool;
|
||||
};
|
||||
|
@ -137,14 +137,14 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
|
||||
|
||||
function getClip(entity: RegionEntity | LayerEntity | InpaintMaskEntity) {
|
||||
const settings = getSettings();
|
||||
const bbox = getBbox();
|
||||
const bboxRect = getBbox().rect;
|
||||
|
||||
if (settings.clipToBbox) {
|
||||
return {
|
||||
x: bbox.x - entity.x,
|
||||
y: bbox.y - entity.y,
|
||||
width: bbox.width,
|
||||
height: bbox.height,
|
||||
x: bboxRect.x - entity.x,
|
||||
y: bboxRect.y - entity.y,
|
||||
width: bboxRect.width,
|
||||
height: bboxRect.height,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
@ -486,7 +486,6 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
|
||||
stage.position(newPos);
|
||||
setStageAttrs({ ...newPos, width: stage.width(), height: stage.height(), scale: newScale });
|
||||
manager.background.render();
|
||||
manager.preview.documentSizeOverlay.render();
|
||||
}
|
||||
}
|
||||
manager.preview.tool.render();
|
||||
@ -502,7 +501,6 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
|
||||
scale: stage.scaleX(),
|
||||
});
|
||||
manager.background.render();
|
||||
manager.preview.documentSizeOverlay.render();
|
||||
manager.preview.tool.render();
|
||||
});
|
||||
|
||||
@ -540,9 +538,8 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
|
||||
} else if (e.key === 'r') {
|
||||
setLastCursorPos(null);
|
||||
setLastMouseDownPos(null);
|
||||
manager.preview.documentSizeOverlay.fitToStage();
|
||||
manager.background.render();
|
||||
manager.preview.documentSizeOverlay.render();
|
||||
// TODO(psyche): restore some kind of fit
|
||||
}
|
||||
manager.preview.tool.render();
|
||||
};
|
||||
|
@ -1,12 +1,17 @@
|
||||
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 { 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 type { IRect } from 'konva/lib/types';
|
||||
import { pick } from 'lodash-es';
|
||||
|
||||
export const bboxReducers = {
|
||||
scaledBboxChanged: (state, action: PayloadAction<Partial<Size>>) => {
|
||||
bboxScaledSizeChanged: (state, action: PayloadAction<Partial<Size>>) => {
|
||||
state.layers.imageCache = null;
|
||||
state.bbox.scaledSize = { ...state.bbox.scaledSize, ...action.payload };
|
||||
},
|
||||
@ -30,4 +35,116 @@ export const bboxReducers = {
|
||||
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>;
|
||||
|
@ -5,7 +5,6 @@ import { deepClone } from 'common/util/deepClone';
|
||||
import { bboxReducers } from 'features/controlLayers/store/bboxReducers';
|
||||
import { compositingReducers } from 'features/controlLayers/store/compositingReducers';
|
||||
import { controlAdaptersReducers } from 'features/controlLayers/store/controlAdaptersReducers';
|
||||
import { documentReducers } from 'features/controlLayers/store/documentReducers';
|
||||
import { initialImageReducers } from 'features/controlLayers/store/initialImageReducers';
|
||||
import { inpaintMaskReducers } from 'features/controlLayers/store/inpaintMaskReducers';
|
||||
import { ipAdaptersReducers } from 'features/controlLayers/store/ipAdaptersReducers';
|
||||
@ -63,12 +62,9 @@ const initialState: CanvasV2State = {
|
||||
width: 50,
|
||||
},
|
||||
},
|
||||
document: {
|
||||
rect: { x: 0, y: 0, width: 512, height: 512 },
|
||||
aspectRatio: deepClone(initialAspectRatioState),
|
||||
},
|
||||
bbox: {
|
||||
rect: { x: 0, y: 0, width: 512, height: 512 },
|
||||
aspectRatio: deepClone(initialAspectRatioState),
|
||||
scaleMethod: 'auto',
|
||||
scaledSize: {
|
||||
width: 512,
|
||||
@ -149,7 +145,6 @@ export const canvasV2Slice = createSlice({
|
||||
...bboxReducers,
|
||||
...inpaintMaskReducers,
|
||||
...sessionReducers,
|
||||
...documentReducers,
|
||||
...initialImageReducers,
|
||||
entitySelected: (state, action: PayloadAction<CanvasEntityIdentifier>) => {
|
||||
state.selectedEntityIdentifier = action.payload;
|
||||
@ -164,7 +159,6 @@ export const canvasV2Slice = createSlice({
|
||||
canvasReset: (state) => {
|
||||
state.bbox = deepClone(initialState.bbox);
|
||||
state.controlAdapters = deepClone(initialState.controlAdapters);
|
||||
state.document = deepClone(initialState.document);
|
||||
state.ipAdapters = deepClone(initialState.ipAdapters);
|
||||
state.layers = deepClone(initialState.layers);
|
||||
state.regions = deepClone(initialState.regions);
|
||||
@ -178,7 +172,6 @@ export const canvasV2Slice = createSlice({
|
||||
});
|
||||
|
||||
export const {
|
||||
bboxChanged,
|
||||
brushWidthChanged,
|
||||
eraserWidthChanged,
|
||||
fillChanged,
|
||||
@ -188,17 +181,18 @@ export const {
|
||||
maskOpacityChanged,
|
||||
entitySelected,
|
||||
allEntitiesDeleted,
|
||||
scaledBboxChanged,
|
||||
bboxScaleMethodChanged,
|
||||
clipToBboxChanged,
|
||||
canvasReset,
|
||||
// document
|
||||
documentWidthChanged,
|
||||
documentHeightChanged,
|
||||
documentAspectRatioLockToggled,
|
||||
documentAspectRatioIdChanged,
|
||||
documentDimensionsSwapped,
|
||||
documentSizeOptimized,
|
||||
// bbox
|
||||
bboxChanged,
|
||||
bboxScaledSizeChanged,
|
||||
bboxScaleMethodChanged,
|
||||
bboxWidthChanged,
|
||||
bboxHeightChanged,
|
||||
bboxAspectRatioLockToggled,
|
||||
bboxAspectRatioIdChanged,
|
||||
bboxDimensionsSwapped,
|
||||
bboxSizeOptimized,
|
||||
// layers
|
||||
layerAdded,
|
||||
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
|
||||
// TODO(psyche): Should we change the document size too?
|
||||
const optimalDimension = getOptimalDimension(model);
|
||||
if (!getIsSizeOptimal(state.document.rect.width, state.document.rect.height, optimalDimension)) {
|
||||
const bboxDims = calculateNewSize(state.document.aspectRatio.value, optimalDimension * optimalDimension);
|
||||
if (!getIsSizeOptimal(state.bbox.rect.width, state.bbox.rect.height, optimalDimension)) {
|
||||
const bboxDims = calculateNewSize(state.bbox.aspectRatio.value, optimalDimension * optimalDimension);
|
||||
state.bbox.rect.width = bboxDims.width;
|
||||
state.bbox.rect.height = bboxDims.height;
|
||||
|
||||
|
@ -847,15 +847,6 @@ export type CanvasV2State = {
|
||||
eraser: { width: number };
|
||||
fill: RgbaColor;
|
||||
};
|
||||
document: {
|
||||
rect: {
|
||||
x: number;
|
||||
y: number;
|
||||
width: ParameterWidth;
|
||||
height: ParameterHeight;
|
||||
};
|
||||
aspectRatio: AspectRatioState;
|
||||
};
|
||||
settings: {
|
||||
imageSmoothing: boolean;
|
||||
maskOpacity: number;
|
||||
@ -872,6 +863,7 @@ export type CanvasV2State = {
|
||||
width: ParameterWidth;
|
||||
height: ParameterHeight;
|
||||
};
|
||||
aspectRatio: AspectRatioState;
|
||||
scaledSize: {
|
||||
width: ParameterWidth;
|
||||
height: ParameterHeight;
|
||||
|
@ -11,9 +11,9 @@ import {
|
||||
getRGId,
|
||||
} from 'features/controlLayers/konva/naming';
|
||||
import {
|
||||
bboxHeightChanged,
|
||||
bboxWidthChanged,
|
||||
caRecalled,
|
||||
documentHeightChanged,
|
||||
documentWidthChanged,
|
||||
ipaRecalled,
|
||||
layerAllDeleted,
|
||||
layerRecalled,
|
||||
@ -115,11 +115,11 @@ const recallScheduler: MetadataRecallFunc<ParameterScheduler> = (scheduler) => {
|
||||
const setSizeOptions = { updateAspectRatio: true, clamp: true };
|
||||
|
||||
const recallWidth: MetadataRecallFunc<ParameterWidth> = (width) => {
|
||||
getStore().dispatch(documentWidthChanged({ width, ...setSizeOptions }));
|
||||
getStore().dispatch(bboxWidthChanged({ width, ...setSizeOptions }));
|
||||
};
|
||||
|
||||
const recallHeight: MetadataRecallFunc<ParameterHeight> = (height) => {
|
||||
getStore().dispatch(documentHeightChanged({ height, ...setSizeOptions }));
|
||||
getStore().dispatch(bboxHeightChanged({ height, ...setSizeOptions }));
|
||||
};
|
||||
|
||||
const recallSteps: MetadataRecallFunc<ParameterSteps> = (steps) => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
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 { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@ -20,7 +20,7 @@ const ParamScaledHeight = () => {
|
||||
|
||||
const onChange = useCallback(
|
||||
(height: number) => {
|
||||
dispatch(scaledBboxChanged({ height }));
|
||||
dispatch(bboxScaledSizeChanged({ height }));
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
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 { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@ -19,7 +19,7 @@ const ParamScaledWidth = () => {
|
||||
const fineStep = useAppSelector((s) => s.config.sd.scaledBoundingBoxWidth.fineStep);
|
||||
const onChange = useCallback(
|
||||
(width: number) => {
|
||||
dispatch(scaledBboxChanged({ width }));
|
||||
dispatch(bboxScaledSizeChanged({ width }));
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
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 { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@ -10,7 +10,7 @@ export const ParamHeight = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
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 sliderMax = useAppSelector((s) => s.config.sd.height.sliderMax);
|
||||
const numberInputMin = useAppSelector((s) => s.config.sd.height.numberInputMin);
|
||||
@ -20,7 +20,7 @@ export const ParamHeight = memo(() => {
|
||||
|
||||
const onChange = useCallback(
|
||||
(v: number) => {
|
||||
dispatch(documentHeightChanged({ height: v }));
|
||||
dispatch(bboxHeightChanged({ height: v }));
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
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 { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@ -9,7 +9,7 @@ import { useTranslation } from 'react-i18next';
|
||||
export const ParamWidth = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
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 sliderMin = useAppSelector((s) => s.config.sd.width.sliderMin);
|
||||
const sliderMax = useAppSelector((s) => s.config.sd.width.sliderMax);
|
||||
@ -20,7 +20,7 @@ export const ParamWidth = memo(() => {
|
||||
|
||||
const onChange = useCallback(
|
||||
(v: number) => {
|
||||
dispatch(documentWidthChanged({ width: v }));
|
||||
dispatch(bboxWidthChanged({ width: v }));
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
@ -16,13 +16,13 @@ import {
|
||||
} from './constants';
|
||||
|
||||
export const AspectRatioIconPreview = memo(() => {
|
||||
const document = useAppSelector((s) => s.canvasV2.document);
|
||||
const bbox = useAppSelector((s) => s.canvasV2.bbox);
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const containerSize = useSize(containerRef);
|
||||
|
||||
const shouldShowIcon = useMemo(
|
||||
() => document.aspectRatio.value < ICON_HIGH_CUTOFF && document.aspectRatio.value > ICON_LOW_CUTOFF,
|
||||
[document.aspectRatio.value]
|
||||
() => bbox.aspectRatio.value < ICON_HIGH_CUTOFF && bbox.aspectRatio.value > ICON_LOW_CUTOFF,
|
||||
[bbox.aspectRatio.value]
|
||||
);
|
||||
|
||||
const { width, height } = useMemo(() => {
|
||||
@ -30,19 +30,19 @@ export const AspectRatioIconPreview = memo(() => {
|
||||
return { width: 0, height: 0 };
|
||||
}
|
||||
|
||||
let width = document.rect.width;
|
||||
let height = document.rect.height;
|
||||
let width = bbox.rect.width;
|
||||
let height = bbox.rect.height;
|
||||
|
||||
if (document.rect.width > document.rect.height) {
|
||||
if (bbox.rect.width > bbox.rect.height) {
|
||||
width = containerSize.width;
|
||||
height = width / document.aspectRatio.value;
|
||||
height = width / bbox.aspectRatio.value;
|
||||
} else {
|
||||
height = containerSize.height;
|
||||
width = height * document.aspectRatio.value;
|
||||
width = height * bbox.aspectRatio.value;
|
||||
}
|
||||
|
||||
return { width, height };
|
||||
}, [containerSize, document.rect.width, document.rect.height, document.aspectRatio.value]);
|
||||
}, [containerSize, bbox.rect.width, bbox.rect.height, bbox.aspectRatio.value]);
|
||||
|
||||
return (
|
||||
<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 type { SingleValue } from 'chakra-react-select';
|
||||
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 { isAspectRatioID } from 'features/parameters/components/DocumentSize/types';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
@ -12,14 +12,14 @@ import { useTranslation } from 'react-i18next';
|
||||
export const AspectRatioSelect = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const id = useAppSelector((s) => s.canvasV2.document.aspectRatio.id);
|
||||
const id = useAppSelector((s) => s.canvasV2.bbox.aspectRatio.id);
|
||||
|
||||
const onChange = useCallback(
|
||||
(v: SingleValue<ComboboxOption>) => {
|
||||
if (!v || !isAspectRatioID(v.value)) {
|
||||
return;
|
||||
}
|
||||
dispatch(documentAspectRatioIdChanged({ id: v.value }));
|
||||
dispatch(bboxAspectRatioIdChanged({ id: v.value }));
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { IconButton } from '@invoke-ai/ui-library';
|
||||
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 { useTranslation } from 'react-i18next';
|
||||
import { PiLockSimpleFill, PiLockSimpleOpenBold } from 'react-icons/pi';
|
||||
@ -8,9 +8,9 @@ import { PiLockSimpleFill, PiLockSimpleOpenBold } from 'react-icons/pi';
|
||||
export const LockAspectRatioButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const isLocked = useAppSelector((s) => s.canvasV2.document.aspectRatio.isLocked);
|
||||
const isLocked = useAppSelector((s) => s.canvasV2.bbox.aspectRatio.isLocked);
|
||||
const onClick = useCallback(() => {
|
||||
dispatch(documentAspectRatioLockToggled());
|
||||
dispatch(bboxAspectRatioLockToggled());
|
||||
}, [dispatch]);
|
||||
|
||||
return (
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { IconButton } from '@invoke-ai/ui-library';
|
||||
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 { getIsSizeTooLarge, getIsSizeTooSmall } from 'features/parameters/util/optimalDimension';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
@ -10,8 +10,8 @@ import { RiSparklingFill } from 'react-icons/ri';
|
||||
export const SetOptimalSizeButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const width = useAppSelector((s) => s.canvasV2.document.rect.width);
|
||||
const height = useAppSelector((s) => s.canvasV2.document.rect.height);
|
||||
const width = useAppSelector((s) => s.canvasV2.bbox.rect.width);
|
||||
const height = useAppSelector((s) => s.canvasV2.bbox.rect.height);
|
||||
const optimalDimension = useAppSelector(selectOptimalDimension);
|
||||
const isSizeTooSmall = useMemo(
|
||||
() => getIsSizeTooSmall(width, height, optimalDimension),
|
||||
@ -22,7 +22,7 @@ export const SetOptimalSizeButton = memo(() => {
|
||||
[height, width, optimalDimension]
|
||||
);
|
||||
const onClick = useCallback(() => {
|
||||
dispatch(documentSizeOptimized());
|
||||
dispatch(bboxSizeOptimized());
|
||||
}, [dispatch]);
|
||||
const tooltip = useMemo(() => {
|
||||
if (isSizeTooSmall) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { IconButton } from '@invoke-ai/ui-library';
|
||||
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 { useTranslation } from 'react-i18next';
|
||||
import { PiArrowsDownUpBold } from 'react-icons/pi';
|
||||
@ -9,7 +9,7 @@ export const SwapDimensionsButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const onClick = useCallback(() => {
|
||||
dispatch(documentDimensionsSwapped());
|
||||
dispatch(bboxDimensionsSwapped());
|
||||
}, [dispatch]);
|
||||
return (
|
||||
<IconButton
|
||||
|
@ -24,8 +24,8 @@ const selector = createMemoizedSelector([selectHrfSlice, selectCanvasV2Slice], (
|
||||
const badges: string[] = [];
|
||||
const isSDXL = model?.base === 'sdxl';
|
||||
|
||||
const { aspectRatio } = canvasV2.document;
|
||||
const { width, height } = canvasV2.document.rect;
|
||||
const { aspectRatio } = canvasV2.bbox;
|
||||
const { width, height } = canvasV2.bbox.rect;
|
||||
|
||||
badges.push(`${width}×${height}`);
|
||||
badges.push(aspectRatio.id);
|
||||
|
Loading…
Reference in New Issue
Block a user