feat(ui): add toggle for clipToBbox

This commit is contained in:
psychedelicious 2024-06-20 10:41:11 +10:00
parent 488ca87787
commit ce8a7bc178
6 changed files with 66 additions and 40 deletions

View File

@ -11,7 +11,7 @@ import {
} from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { MaskOpacity } from 'features/controlLayers/components/MaskOpacity';
import { invertScrollChanged } from 'features/controlLayers/store/canvasV2Slice';
import { clipToBboxChanged, invertScrollChanged } from 'features/controlLayers/store/canvasV2Slice';
import type { ChangeEvent } from 'react';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
@ -20,11 +20,16 @@ import { RiSettings4Fill } from 'react-icons/ri';
const ControlLayersSettingsPopover = () => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const clipToBbox = useAppSelector((s) => s.canvasV2.settings.clipToBbox);
const invertScroll = useAppSelector((s) => s.canvasV2.tool.invertScroll);
const onChangeInvertScroll = useCallback(
(e: ChangeEvent<HTMLInputElement>) => dispatch(invertScrollChanged(e.target.checked)),
[dispatch]
);
const onChangeClipToBbox = useCallback(
(e: ChangeEvent<HTMLInputElement>) => dispatch(clipToBboxChanged(e.target.checked)),
[dispatch]
);
return (
<Popover isLazy>
<PopoverTrigger>
@ -38,6 +43,10 @@ const ControlLayersSettingsPopover = () => {
<FormLabel flexGrow={1}>{t('unifiedCanvas.invertBrushSizeScrollDirection')}</FormLabel>
<Checkbox isChecked={invertScroll} onChange={onChangeInvertScroll} />
</FormControl>
<FormControl w="full">
<FormLabel flexGrow={1}>{t('unifiedCanvas.clipToBbox')}</FormLabel>
<Checkbox isChecked={clipToBbox} onChange={onChangeClipToBbox} />
</FormControl>
</Flex>
</PopoverBody>
</PopoverContent>

View File

@ -53,6 +53,7 @@ type Arg = {
setSpaceKey: (val: boolean) => void;
getDocument: () => CanvasV2State['document'];
getBbox: () => CanvasV2State['bbox'];
getSettings: () => CanvasV2State['settings'];
onBrushLineAdded: (arg: BrushLineAddedArg, entityType: CanvasEntity['type']) => void;
onEraserLineAdded: (arg: EraserLineAddedArg, entityType: CanvasEntity['type']) => void;
onPointAddedToLine: (arg: PointAddedToLineArg, entityType: CanvasEntity['type']) => void;
@ -155,6 +156,7 @@ export const setStageEventHandlers = ({
setSpaceKey,
getDocument,
getBbox,
getSettings,
onBrushLineAdded,
onEraserLineAdded,
onPointAddedToLine,
@ -203,6 +205,17 @@ export const setStageEventHandlers = ({
if (toolState.selected === 'brush') {
const bbox = getBbox();
const settings = getSettings();
const clip = settings.clipToBbox
? {
x: bbox.x,
y: bbox.y,
width: bbox.width,
height: bbox.height,
}
: null;
if (e.evt.shiftKey) {
const lastAddedPoint = getLastAddedPoint();
// Create a straight line if holding shift
@ -218,12 +231,7 @@ export const setStageEventHandlers = ({
],
color: getCurrentFill(),
width: toolState.brush.width,
clip: {
x: bbox.x,
y: bbox.y,
width: bbox.width,
height: bbox.height,
},
clip,
},
selectedEntity.type
);
@ -240,12 +248,7 @@ export const setStageEventHandlers = ({
],
color: getCurrentFill(),
width: toolState.brush.width,
clip: {
x: bbox.x,
y: bbox.y,
width: bbox.width,
height: bbox.height,
},
clip,
},
selectedEntity.type
);
@ -255,6 +258,16 @@ export const setStageEventHandlers = ({
if (toolState.selected === 'eraser') {
const bbox = getBbox();
const settings = getSettings();
const clip = settings.clipToBbox
? {
x: bbox.x,
y: bbox.y,
width: bbox.width,
height: bbox.height,
}
: null;
if (e.evt.shiftKey) {
// Create a straight line if holding shift
const lastAddedPoint = getLastAddedPoint();
@ -269,12 +282,7 @@ export const setStageEventHandlers = ({
pos.y - selectedEntity.y,
],
width: toolState.eraser.width,
clip: {
x: bbox.x,
y: bbox.y,
width: bbox.width,
height: bbox.height,
},
clip,
},
selectedEntity.type
);
@ -290,12 +298,7 @@ export const setStageEventHandlers = ({
pos.y - selectedEntity.y,
],
width: toolState.eraser.width,
clip: {
x: bbox.x,
y: bbox.y,
width: bbox.width,
height: bbox.height,
},
clip,
},
selectedEntity.type
);
@ -402,6 +405,16 @@ export const setStageEventHandlers = ({
);
} else {
const bbox = getBbox();
const settings = getSettings();
const clip = settings.clipToBbox
? {
x: bbox.x,
y: bbox.y,
width: bbox.width,
height: bbox.height,
}
: null;
// Start a new line
onBrushLineAdded(
{
@ -414,12 +427,7 @@ export const setStageEventHandlers = ({
],
width: toolState.brush.width,
color: getCurrentFill(),
clip: {
x: bbox.x,
y: bbox.y,
width: bbox.width,
height: bbox.height,
},
clip,
},
selectedEntity.type
);
@ -441,6 +449,16 @@ export const setStageEventHandlers = ({
);
} else {
const bbox = getBbox();
const settings = getSettings();
const clip = settings.clipToBbox
? {
x: bbox.x,
y: bbox.y,
width: bbox.width,
height: bbox.height,
}
: null;
// Start a new line
onEraserLineAdded(
{
@ -452,12 +470,7 @@ export const setStageEventHandlers = ({
pos.y - selectedEntity.y,
],
width: toolState.eraser.width,
clip: {
x: bbox.x,
y: bbox.y,
width: bbox.width,
height: bbox.height,
},
clip,
},
selectedEntity.type
);

View File

@ -33,8 +33,6 @@ const getControlAdapter = (manager: KonvaNodeManager, entity: ControlAdapterEnti
listening: false,
});
const konvaObjectGroup = createObjectGroup(konvaLayer, CA_LAYER_OBJECT_GROUP_NAME);
konvaLayer.add(konvaObjectGroup);
manager.stage.add(konvaLayer);
return manager.add(entity.id, konvaLayer, konvaObjectGroup);
};

View File

@ -3,8 +3,8 @@ import type { Store } from '@reduxjs/toolkit';
import { logger } from 'app/logging/logger';
import { $isDebugging } from 'app/store/nanostores/isDebugging';
import type { RootState } from 'app/store/store';
import { KonvaNodeManager } from 'features/controlLayers/konva/nodeManager';
import { setStageEventHandlers } from 'features/controlLayers/konva/events';
import { KonvaNodeManager } from 'features/controlLayers/konva/nodeManager';
import { arrangeEntities } from 'features/controlLayers/konva/renderers/arrange';
import { renderBackgroundLayer } from 'features/controlLayers/konva/renderers/background';
import { updateBboxes } from 'features/controlLayers/konva/renderers/bbox';
@ -209,6 +209,7 @@ export const initializeRenderer = (
const getBbox = () => getState().canvasV2.bbox;
const getDocument = () => getState().canvasV2.document;
const getToolState = () => getState().canvasV2.tool;
const getSettings = () => getState().canvasV2.settings;
// Read-write state, ephemeral interaction state
let isDrawing = false;
@ -268,6 +269,7 @@ export const initializeRenderer = (
setStageAttrs: $stageAttrs.set,
getDocument,
getBbox,
getSettings,
onBrushLineAdded,
onEraserLineAdded,
onPointAddedToLine,

View File

@ -184,6 +184,7 @@ export const {
allEntitiesDeleted,
scaledBboxChanged,
bboxScaleMethodChanged,
clipToBboxChanged,
// layers
layerAdded,
layerRecalled,

View File

@ -5,4 +5,7 @@ export const settingsReducers = {
maskOpacityChanged: (state, action: PayloadAction<number>) => {
state.settings.maskOpacity = action.payload;
},
clipToBboxChanged: (state, action: PayloadAction<boolean>) => {
state.settings.clipToBbox = action.payload;
},
} satisfies SliceCaseReducers<CanvasV2State>;