feat(ui): use position and dimensions instead of separate x,y,width,height attrs

This commit is contained in:
psychedelicious 2024-07-17 11:08:19 +10:00
parent 56237328f1
commit 44f91026e1
16 changed files with 130 additions and 130 deletions

View File

@ -58,7 +58,7 @@ export const addStagingListeners = (startAppListening: AppStartListening) => {
assert(stagingAreaImage, 'No staged image found to accept');
const { x, y } = state.canvasV2.bbox.rect;
api.dispatch(layerAddedFromStagingArea({ stagingAreaImage, pos: { x, y } }));
api.dispatch(layerAddedFromStagingArea({ stagingAreaImage, position: { x, y } }));
api.dispatch(sessionStagingAreaReset());
},
});

View File

@ -24,10 +24,10 @@ export const HeadsUpDisplay = memo(() => {
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="Stage Pos" value={`${round(stageAttrs.x, 3)}, ${round(stageAttrs.y, 3)}`} />
<HUDItem label="Stage Pos" value={`${round(stageAttrs.position.x, 3)}, ${round(stageAttrs.position.y, 3)}`} />
<HUDItem
label="Stage Size"
value={`${round(stageAttrs.width / stageAttrs.scale, 2)}×${round(stageAttrs.height / stageAttrs.scale, 2)} px`}
value={`${round(stageAttrs.dimensions.width / stageAttrs.scale, 2)}×${round(stageAttrs.dimensions.height / stageAttrs.scale, 2)} px`}
/>
<HUDItem label="BBox Size" value={`${bbox.rect.width}×${bbox.rect.height} px`} />
<HUDItem label="BBox Position" value={`${bbox.rect.x}, ${bbox.rect.y}`} />

View File

@ -42,12 +42,15 @@ export class CanvasControlAdapter {
});
this.transformer.on('transformend', () => {
this.manager.stateApi.onScaleChanged(
{ id: this.id, scale: this.group.scaleX(), x: this.group.x(), y: this.group.y() },
{ id: this.id, scale: this.group.scaleX(), position: { x: this.group.x(), y: this.group.y() } },
'control_adapter'
);
});
this.transformer.on('dragend', () => {
this.manager.stateApi.onPosChanged({ id: this.id, x: this.group.x(), y: this.group.y() }, 'control_adapter');
this.manager.stateApi.onPosChanged(
{ id: this.id, position: { x: this.group.x(), y: this.group.y() } },
'control_adapter'
);
});
this.layer.add(this.transformer);
@ -60,8 +63,8 @@ export class CanvasControlAdapter {
// Update the layer's position and listening state
this.group.setAttrs({
x: controlAdapterState.x,
y: controlAdapterState.y,
x: controlAdapterState.position.x,
y: controlAdapterState.position.y,
scaleX: 1,
scaleY: 1,
});

View File

@ -42,7 +42,7 @@ export class CanvasInitialImage {
}
if (!this.image) {
this.image = await new CanvasImage(this.initialImageState.imageObject, {});
this.image = await new CanvasImage(this.initialImageState.imageObject);
this.objectsGroup.add(this.image.konvaImageGroup);
await this.image.update(this.initialImageState.imageObject, true);
} else if (!this.image.isLoading && !this.image.isError) {

View File

@ -46,12 +46,15 @@ export class CanvasInpaintMask {
});
this.transformer.on('transformend', () => {
this.manager.stateApi.onScaleChanged(
{ id: this.id, scale: this.group.scaleX(), x: this.group.x(), y: this.group.y() },
{ id: this.id, scale: this.group.scaleX(), position: { x: this.group.x(), y: this.group.y() } },
'inpaint_mask'
);
});
this.transformer.on('dragend', () => {
this.manager.stateApi.onPosChanged({ id: this.id, x: this.group.x(), y: this.group.y() }, 'inpaint_mask');
this.manager.stateApi.onPosChanged(
{ id: this.id, position: { x: this.group.x(), y: this.group.y() } },
'inpaint_mask'
);
});
this.layer.add(this.transformer);
@ -103,8 +106,8 @@ export class CanvasInpaintMask {
// Update the layer's position and listening state
this.group.setAttrs({
x: inpaintMaskState.x,
y: inpaintMaskState.y,
x: inpaintMaskState.position.x,
y: inpaintMaskState.position.y,
scaleX: 1,
scaleY: 1,
});

View File

@ -48,12 +48,12 @@ export class CanvasLayer {
});
this.transformer.on('transformend', () => {
this.manager.stateApi.onScaleChanged(
{ id: this.id, scale: this.group.scaleX(), x: this.group.x(), y: this.group.y() },
{ id: this.id, scale: this.group.scaleX(), position: { x: this.group.x(), y: this.group.y() } },
'layer'
);
});
this.transformer.on('dragend', () => {
this.manager.stateApi.onPosChanged({ id: this.id, x: this.group.x(), y: this.group.y() }, 'layer');
this.manager.stateApi.onPosChanged({ id: this.id, position: { x: this.group.x(), y: this.group.y() } }, 'layer');
});
this.layer.add(this.transformer);
@ -99,8 +99,8 @@ export class CanvasLayer {
// Update the layer's position and listening state
this.group.setAttrs({
x: layerState.x,
y: layerState.y,
x: layerState.position.x,
y: layerState.position.y,
scaleX: 1,
scaleY: 1,
});

View File

@ -212,10 +212,8 @@ export class CanvasManager {
this.stage.width(this.container.offsetWidth);
this.stage.height(this.container.offsetHeight);
this.stateApi.setStageAttrs({
x: this.stage.x(),
y: this.stage.y(),
width: this.stage.width(),
height: this.stage.height(),
position: { x: this.stage.x(), y: this.stage.y() },
dimensions: { width: this.stage.width(), height: this.stage.height() },
scale: this.stage.scaleX(),
});
this.background.render();

View File

@ -47,12 +47,15 @@ export class CanvasRegion {
});
this.transformer.on('transformend', () => {
this.manager.stateApi.onScaleChanged(
{ id: this.id, scale: this.group.scaleX(), x: this.group.x(), y: this.group.y() },
{ id: this.id, scale: this.group.scaleX(), position: { x: this.group.x(), y: this.group.y() } },
'regional_guidance'
);
});
this.transformer.on('dragend', () => {
this.manager.stateApi.onPosChanged({ id: this.id, x: this.group.x(), y: this.group.y() }, 'regional_guidance');
this.manager.stateApi.onPosChanged(
{ id: this.id, position: { x: this.group.x(), y: this.group.y() } },
'regional_guidance'
);
});
this.layer.add(this.transformer);
@ -104,8 +107,8 @@ export class CanvasRegion {
// Update the layer's position and listening state
this.group.setAttrs({
x: regionState.x,
y: regionState.y,
x: regionState.position.x,
y: regionState.position.y,
scaleX: 1,
scaleY: 1,
});

View File

@ -47,7 +47,7 @@ import type {
BrushLine,
CanvasEntity,
EraserLine,
PosChangedArg,
PositionChangedArg,
RectShape,
ScaleChangedArg,
Tool,
@ -70,7 +70,7 @@ export class CanvasStateApi {
return this.store.getState().canvasV2;
};
onPosChanged = (arg: PosChangedArg, entityType: CanvasEntity['type']) => {
onPosChanged = (arg: PositionChangedArg, entityType: CanvasEntity['type']) => {
log.debug('onPosChanged');
if (entityType === 'layer') {
this.store.dispatch(layerTranslated(arg));

View File

@ -2,9 +2,9 @@ import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
import { getScaledCursorPosition } from 'features/controlLayers/konva/util';
import type {
CanvasV2State,
Coordinate,
InpaintMaskEntity,
LayerEntity,
Coordinate,
RegionEntity,
Tool,
} from 'features/controlLayers/store/types';
@ -141,15 +141,15 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
if (settings.clipToBbox) {
return {
x: bboxRect.x - entity.x,
y: bboxRect.y - entity.y,
x: bboxRect.x - entity.position.x,
y: bboxRect.y - entity.position.y,
width: bboxRect.width,
height: bboxRect.height,
};
} else {
return {
x: -stage.x() / stage.scaleX() - entity.x,
y: -stage.y() / stage.scaleY() - entity.y,
x: -stage.x() / stage.scaleX() - entity.position.x,
y: -stage.y() / stage.scaleY() - entity.position.y,
width: stage.width() / stage.scaleX(),
height: stage.height() / stage.scaleY(),
};
@ -194,8 +194,8 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
// The last point of the last line is already normalized to the entity's coordinates
lastLinePoint.x,
lastLinePoint.y,
pos.x - selectedEntity.x,
pos.y - selectedEntity.y,
pos.x - selectedEntity.position.x,
pos.y - selectedEntity.position.y,
],
strokeWidth: toolState.brush.width,
color: getCurrentFill(),
@ -208,7 +208,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
await selectedEntityAdapter.setDrawingBuffer({
id: getBrushLineId(selectedEntityAdapter.id, uuidv4()),
type: 'brush_line',
points: [pos.x - selectedEntity.x, pos.y - selectedEntity.y],
points: [pos.x - selectedEntity.position.x, pos.y - selectedEntity.position.y],
strokeWidth: toolState.brush.width,
color: getCurrentFill(),
clip: getClip(selectedEntity),
@ -231,8 +231,8 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
// The last point of the last line is already normalized to the entity's coordinates
lastLinePoint.x,
lastLinePoint.y,
pos.x - selectedEntity.x,
pos.y - selectedEntity.y,
pos.x - selectedEntity.position.x,
pos.y - selectedEntity.position.y,
],
strokeWidth: toolState.eraser.width,
clip: getClip(selectedEntity),
@ -244,7 +244,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
await selectedEntityAdapter.setDrawingBuffer({
id: getEraserLineId(selectedEntityAdapter.id, uuidv4()),
type: 'eraser_line',
points: [pos.x - selectedEntity.x, pos.y - selectedEntity.y],
points: [pos.x - selectedEntity.position.x, pos.y - selectedEntity.position.y],
strokeWidth: toolState.eraser.width,
clip: getClip(selectedEntity),
});
@ -259,8 +259,8 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
await selectedEntityAdapter.setDrawingBuffer({
id: getRectShapeId(selectedEntityAdapter.id, uuidv4()),
type: 'rect_shape',
x: pos.x - selectedEntity.x,
y: pos.y - selectedEntity.y,
x: pos.x - selectedEntity.position.x,
y: pos.y - selectedEntity.position.y,
width: 0,
height: 0,
color: getCurrentFill(),
@ -342,7 +342,10 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
if (drawingBuffer?.type === 'brush_line') {
const nextPoint = getNextPoint(pos, toolState, getLastPointOfLine(drawingBuffer.points));
if (nextPoint) {
drawingBuffer.points.push(nextPoint.x - selectedEntity.x, nextPoint.y - selectedEntity.y);
drawingBuffer.points.push(
nextPoint.x - selectedEntity.position.x,
nextPoint.y - selectedEntity.position.y
);
await selectedEntityAdapter.setDrawingBuffer(drawingBuffer);
setLastAddedPoint(nextPoint);
}
@ -356,7 +359,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
await selectedEntityAdapter.setDrawingBuffer({
id: getBrushLineId(selectedEntityAdapter.id, uuidv4()),
type: 'brush_line',
points: [pos.x - selectedEntity.x, pos.y - selectedEntity.y],
points: [pos.x - selectedEntity.position.x, pos.y - selectedEntity.position.y],
strokeWidth: toolState.brush.width,
color: getCurrentFill(),
clip: getClip(selectedEntity),
@ -371,7 +374,10 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
if (drawingBuffer.type === 'eraser_line') {
const nextPoint = getNextPoint(pos, toolState, getLastPointOfLine(drawingBuffer.points));
if (nextPoint) {
drawingBuffer.points.push(nextPoint.x - selectedEntity.x, nextPoint.y - selectedEntity.y);
drawingBuffer.points.push(
nextPoint.x - selectedEntity.position.x,
nextPoint.y - selectedEntity.position.y
);
await selectedEntityAdapter.setDrawingBuffer(drawingBuffer);
setLastAddedPoint(nextPoint);
}
@ -385,7 +391,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
await selectedEntityAdapter.setDrawingBuffer({
id: getEraserLineId(selectedEntityAdapter.id, uuidv4()),
type: 'eraser_line',
points: [pos.x - selectedEntity.x, pos.y - selectedEntity.y],
points: [pos.x - selectedEntity.position.x, pos.y - selectedEntity.position.y],
strokeWidth: toolState.eraser.width,
clip: getClip(selectedEntity),
});
@ -397,8 +403,8 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
const drawingBuffer = selectedEntityAdapter.getDrawingBuffer();
if (drawingBuffer) {
if (drawingBuffer.type === 'rect_shape') {
drawingBuffer.width = pos.x - selectedEntity.x - drawingBuffer.x;
drawingBuffer.height = pos.y - selectedEntity.y - drawingBuffer.y;
drawingBuffer.width = pos.x - selectedEntity.position.x - drawingBuffer.x;
drawingBuffer.height = pos.y - selectedEntity.position.y - drawingBuffer.y;
await selectedEntityAdapter.setDrawingBuffer(drawingBuffer);
} else {
await selectedEntityAdapter.setDrawingBuffer(null);
@ -429,16 +435,16 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
) {
const drawingBuffer = selectedEntityAdapter.getDrawingBuffer();
if (toolState.selected === 'brush' && drawingBuffer?.type === 'brush_line') {
drawingBuffer.points.push(pos.x - selectedEntity.x, pos.y - selectedEntity.y);
drawingBuffer.points.push(pos.x - selectedEntity.position.x, pos.y - selectedEntity.position.y);
await selectedEntityAdapter.setDrawingBuffer(drawingBuffer);
selectedEntityAdapter.finalizeDrawingBuffer();
} else if (toolState.selected === 'eraser' && drawingBuffer?.type === 'eraser_line') {
drawingBuffer.points.push(pos.x - selectedEntity.x, pos.y - selectedEntity.y);
drawingBuffer.points.push(pos.x - selectedEntity.position.x, pos.y - selectedEntity.position.y);
await selectedEntityAdapter.setDrawingBuffer(drawingBuffer);
selectedEntityAdapter.finalizeDrawingBuffer();
} else if (toolState.selected === 'rect' && drawingBuffer?.type === 'rect_shape') {
drawingBuffer.width = pos.x - selectedEntity.x - drawingBuffer.x;
drawingBuffer.height = pos.y - selectedEntity.y - drawingBuffer.y;
drawingBuffer.width = pos.x - selectedEntity.position.x - drawingBuffer.x;
drawingBuffer.height = pos.y - selectedEntity.position.y - drawingBuffer.y;
await selectedEntityAdapter.setDrawingBuffer(drawingBuffer);
selectedEntityAdapter.finalizeDrawingBuffer();
}
@ -484,7 +490,11 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
stage.scaleX(newScale);
stage.scaleY(newScale);
stage.position(newPos);
setStageAttrs({ ...newPos, width: stage.width(), height: stage.height(), scale: newScale });
setStageAttrs({
position: newPos,
dimensions: { width: stage.width(), height: stage.height() },
scale: newScale,
});
manager.background.render();
}
}
@ -494,10 +504,8 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
//#region dragmove
stage.on('dragmove', () => {
setStageAttrs({
x: Math.floor(stage.x()),
y: Math.floor(stage.y()),
width: stage.width(),
height: stage.height(),
position: { x: Math.floor(stage.x()), y: Math.floor(stage.y()) },
dimensions: { width: stage.width(), height: stage.height() },
scale: stage.scaleX(),
});
manager.background.render();
@ -508,10 +516,8 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
stage.on('dragend', () => {
// Stage position should always be an integer, else we get fractional pixels which are blurry
setStageAttrs({
x: Math.floor(stage.x()),
y: Math.floor(stage.y()),
width: stage.width(),
height: stage.height(),
position: { x: Math.floor(stage.x()), y: Math.floor(stage.y()) },
dimensions: { width: stage.width(), height: stage.height() },
scale: stage.scaleX(),
});
manager.preview.tool.render();

View File

@ -50,8 +50,10 @@ const initialState: CanvasV2State = {
imageCache: null,
isEnabled: true,
objects: [],
x: 0,
y: 0,
position: {
x: 0,
y: 0,
},
},
tool: {
selected: 'view',
@ -369,10 +371,8 @@ const migrate = (state: any): any => {
// Ephemeral state that does not need to be in redux
export const $isPreviewVisible = atom(true);
export const $stageAttrs = atom<StageAttrs>({
x: 0,
y: 0,
width: 0,
height: 0,
position: { x: 0, y: 0 },
dimensions: { width: 0, height: 0 },
scale: 0,
});
export const $shouldShowStagedImage = atom(true);

View File

@ -14,6 +14,7 @@ import type {
ControlNetConfig,
ControlNetData,
Filter,
PositionChangedArg,
ProcessorConfig,
ScaleChangedArg,
T2IAdapterConfig,
@ -35,8 +36,7 @@ export const controlAdaptersReducers = {
state.controlAdapters.entities.push({
id,
type: 'control_adapter',
x: 0,
y: 0,
position: { x: 0, y: 0 },
bbox: null,
bboxNeedsUpdate: false,
isEnabled: true,
@ -64,17 +64,16 @@ export const controlAdaptersReducers = {
}
ca.isEnabled = !ca.isEnabled;
},
caTranslated: (state, action: PayloadAction<{ id: string; x: number; y: number }>) => {
const { id, x, y } = action.payload;
caTranslated: (state, action: PayloadAction<PositionChangedArg>) => {
const { id, position } = action.payload;
const ca = selectCA(state, id);
if (!ca) {
return;
}
ca.x = x;
ca.y = y;
ca.position = position;
},
caScaled: (state, action: PayloadAction<ScaleChangedArg>) => {
const { id, scale, x, y } = action.payload;
const { id, scale, position } = action.payload;
const ca = selectCA(state, id);
if (!ca) {
return;
@ -92,8 +91,7 @@ export const controlAdaptersReducers = {
ca.processedImageObject.height *= scale;
ca.processedImageObject.width *= scale;
}
ca.x = x;
ca.y = y;
ca.position = position;
ca.bboxNeedsUpdate = true;
state.layers.imageCache = null;
},

View File

@ -2,6 +2,7 @@ import type { PayloadAction, SliceCaseReducers } from '@reduxjs/toolkit';
import type {
BrushLine,
CanvasV2State,
Coordinate,
EraserLine,
InpaintMaskEntity,
RectShape,
@ -28,13 +29,12 @@ export const inpaintMaskReducers = {
imIsEnabledToggled: (state) => {
state.inpaintMask.isEnabled = !state.inpaintMask.isEnabled;
},
imTranslated: (state, action: PayloadAction<{ x: number; y: number }>) => {
const { x, y } = action.payload;
state.inpaintMask.x = x;
state.inpaintMask.y = y;
imTranslated: (state, action: PayloadAction<{ position: Coordinate }>) => {
const { position } = action.payload;
state.inpaintMask.position = position;
},
imScaled: (state, action: PayloadAction<ScaleChangedArg>) => {
const { scale, x, y } = action.payload;
const { scale, position } = action.payload;
for (const obj of state.inpaintMask.objects) {
if (obj.type === 'brush_line') {
obj.points = obj.points.map((point) => point * scale);
@ -49,8 +49,7 @@ export const inpaintMaskReducers = {
obj.width *= scale;
}
}
state.inpaintMask.x = x;
state.inpaintMask.y = y;
state.inpaintMask.position = position;
state.inpaintMask.bboxNeedsUpdate = true;
state.inpaintMask.imageCache = null;
},

View File

@ -8,10 +8,11 @@ import { v4 as uuidv4 } from 'uuid';
import type {
BrushLine,
CanvasV2State,
Coordinate,
EraserLine,
ImageObjectAddedArg,
LayerEntity,
Coordinate,
PositionChangedArg,
RectShape,
ScaleChangedArg,
StagingAreaImage,
@ -37,8 +38,7 @@ export const layersReducers = {
bboxNeedsUpdate: false,
objects: [],
opacity: 1,
x: 0,
y: 0,
position: { x: 0, y: 0 },
});
state.selectedEntityIdentifier = { type: 'layer', id };
state.layers.imageCache = null;
@ -48,9 +48,9 @@ export const layersReducers = {
layerAddedFromStagingArea: {
reducer: (
state,
action: PayloadAction<{ id: string; objectId: string; stagingAreaImage: StagingAreaImage; pos: Coordinate }>
action: PayloadAction<{ id: string; objectId: string; stagingAreaImage: StagingAreaImage; position: Coordinate }>
) => {
const { id, objectId, stagingAreaImage, pos } = action.payload;
const { id, objectId, stagingAreaImage, position } = action.payload;
const { imageDTO, offsetX, offsetY } = stagingAreaImage;
const imageObject = imageDTOToImageObject(id, objectId, imageDTO);
state.layers.entities.push({
@ -61,13 +61,12 @@ export const layersReducers = {
bboxNeedsUpdate: false,
objects: [imageObject],
opacity: 1,
x: pos.x + offsetX,
y: pos.y + offsetY,
position: { x: position.x + offsetX, y: position.y + offsetY },
});
state.selectedEntityIdentifier = { type: 'layer', id };
state.layers.imageCache = null;
},
prepare: (payload: { stagingAreaImage: StagingAreaImage; pos: Coordinate }) => ({
prepare: (payload: { stagingAreaImage: StagingAreaImage; position: Coordinate }) => ({
payload: { ...payload, id: uuidv4(), objectId: uuidv4() },
}),
},
@ -86,14 +85,13 @@ export const layersReducers = {
layer.isEnabled = !layer.isEnabled;
state.layers.imageCache = null;
},
layerTranslated: (state, action: PayloadAction<{ id: string; x: number; y: number }>) => {
const { id, x, y } = action.payload;
layerTranslated: (state, action: PayloadAction<PositionChangedArg>) => {
const { id, position } = action.payload;
const layer = selectLayer(state, id);
if (!layer) {
return;
}
layer.x = x;
layer.y = y;
layer.position = position;
state.layers.imageCache = null;
},
layerBboxChanged: (state, action: PayloadAction<{ id: string; bbox: IRect | null }>) => {
@ -121,8 +119,7 @@ export const layersReducers = {
layer.bbox = null;
layer.bboxNeedsUpdate = false;
state.layers.imageCache = null;
layer.x = 0;
layer.y = 0;
layer.position = { x: 0, y: 0 };
},
layerDeleted: (state, action: PayloadAction<{ id: string }>) => {
const { id } = action.payload;
@ -212,7 +209,7 @@ export const layersReducers = {
state.layers.imageCache = null;
},
layerScaled: (state, action: PayloadAction<ScaleChangedArg>) => {
const { id, scale, x, y } = action.payload;
const { id, scale, position } = action.payload;
const layer = selectLayer(state, id);
if (!layer) {
return;
@ -236,8 +233,7 @@ export const layersReducers = {
obj.width *= scale;
}
}
layer.x = x;
layer.y = y;
layer.position = position;
layer.bboxNeedsUpdate = true;
state.layers.imageCache = null;
},

View File

@ -6,6 +6,7 @@ import type {
CLIPVisionModelV2,
EraserLine,
IPMethodV2,
PositionChangedArg,
RectShape,
ScaleChangedArg,
} from 'features/controlLayers/store/types';
@ -61,8 +62,7 @@ export const regionsReducers = {
bboxNeedsUpdate: false,
objects: [],
fill: getRGMaskFill(state),
x: 0,
y: 0,
position: { x: 0, y: 0 },
autoNegative: 'invert',
positivePrompt: '',
negativePrompt: null,
@ -97,16 +97,15 @@ export const regionsReducers = {
rg.isEnabled = !rg.isEnabled;
}
},
rgTranslated: (state, action: PayloadAction<{ id: string; x: number; y: number }>) => {
const { id, x, y } = action.payload;
rgTranslated: (state, action: PayloadAction<PositionChangedArg>) => {
const { id, position } = action.payload;
const rg = selectRG(state, id);
if (rg) {
rg.x = x;
rg.y = y;
rg.position = position;
}
},
rgScaled: (state, action: PayloadAction<ScaleChangedArg>) => {
const { id, scale, x, y } = action.payload;
const { id, scale, position } = action.payload;
const rg = selectRG(state, id);
if (!rg) {
return;
@ -125,8 +124,7 @@ export const regionsReducers = {
obj.width *= scale;
}
}
rg.x = x;
rg.y = y;
rg.position = position;
rg.bboxNeedsUpdate = true;
state.layers.imageCache = null;
},

View File

@ -506,6 +506,18 @@ export const RGBA_RED: RgbaColor = { r: 255, g: 0, b: 0, a: 1 };
const zOpacity = z.number().gte(0).lte(1);
const zDimensions = z.object({
width: z.number().int().positive(),
height: z.number().int().positive(),
});
export type Dimensions = z.infer<typeof zDimensions>;
const zCoordinate = z.object({
x: z.number(),
y: z.number(),
});
export type Coordinate = z.infer<typeof zCoordinate>;
const zRect = z.object({
x: z.number(),
y: z.number(),
@ -566,8 +578,7 @@ export const zLayerEntity = z.object({
id: zId,
type: z.literal('layer'),
isEnabled: z.boolean(),
x: z.number(),
y: z.number(),
position: zCoordinate,
bbox: zRect.nullable(),
bboxNeedsUpdate: z.boolean(),
opacity: zOpacity,
@ -631,8 +642,7 @@ export const zRegionEntity = z.object({
id: zId,
type: z.literal('regional_guidance'),
isEnabled: z.boolean(),
x: z.number(),
y: z.number(),
position: zCoordinate,
bbox: zRect.nullable(),
bboxNeedsUpdate: z.boolean(),
objects: z.array(zMaskObject),
@ -658,8 +668,7 @@ const zInpaintMaskEntity = z.object({
id: z.literal('inpaint_mask'),
type: z.literal('inpaint_mask'),
isEnabled: z.boolean(),
x: z.number(),
y: z.number(),
position: zCoordinate,
bbox: zRect.nullable(),
bboxNeedsUpdate: z.boolean(),
objects: z.array(zMaskObject),
@ -682,8 +691,7 @@ const zControlAdapterEntityBase = z.object({
id: zId,
type: z.literal('control_adapter'),
isEnabled: z.boolean(),
x: z.number(),
y: z.number(),
position: zCoordinate,
bbox: zRect.nullable(),
bboxNeedsUpdate: z.boolean(),
opacity: zOpacity,
@ -809,18 +817,6 @@ export type CanvasEntity =
| InitialImageEntity;
export type CanvasEntityIdentifier = Pick<CanvasEntity, 'id' | 'type'>;
const zDimensions = z.object({
width: z.number().int().positive(),
height: z.number().int().positive(),
});
export type Dimensions = z.infer<typeof zDimensions>;
const zCoordinate = z.object({
x: z.number(),
y: z.number(),
});
export type Coordinate = z.infer<typeof zCoordinate>;
export type LoRA = {
id: string;
isEnabled: boolean;
@ -926,9 +922,9 @@ export type CanvasV2State = {
};
};
export type StageAttrs = { x: number; y: number; width: number; height: number; scale: number };
export type PosChangedArg = { id: string; x: number; y: number };
export type ScaleChangedArg = { id: string; scale: number; x: number; y: number };
export type StageAttrs = { position: Coordinate; dimensions: Dimensions; scale: number };
export type PositionChangedArg = { id: string; position: Coordinate };
export type ScaleChangedArg = { id: string; scale: number; position: Coordinate };
export type BboxChangedArg = { id: string; bbox: Rect | null };
export type EraserLineAddedArg = {
id: string;
@ -939,7 +935,7 @@ export type EraserLineAddedArg = {
export type BrushLineAddedArg = EraserLineAddedArg & { color: RgbaColor };
export type PointAddedToLineArg = { id: string; point: [number, number] };
export type RectShapeAddedArg = { id: string; rect: IRect; color: RgbaColor };
export type ImageObjectAddedArg = { id: string; imageDTO: ImageDTO; pos?: Coordinate };
export type ImageObjectAddedArg = { id: string; imageDTO: ImageDTO; position?: Coordinate };
//#region Type guards
export const isLine = (obj: RenderableObject): obj is BrushLine | EraserLine => {