mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): add toggle for clipToBbox
This commit is contained in:
parent
488ca87787
commit
ce8a7bc178
@ -11,7 +11,7 @@ import {
|
|||||||
} from '@invoke-ai/ui-library';
|
} from '@invoke-ai/ui-library';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { MaskOpacity } from 'features/controlLayers/components/MaskOpacity';
|
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 type { ChangeEvent } from 'react';
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@ -20,11 +20,16 @@ import { RiSettings4Fill } from 'react-icons/ri';
|
|||||||
const ControlLayersSettingsPopover = () => {
|
const ControlLayersSettingsPopover = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
const clipToBbox = useAppSelector((s) => s.canvasV2.settings.clipToBbox);
|
||||||
const invertScroll = useAppSelector((s) => s.canvasV2.tool.invertScroll);
|
const invertScroll = useAppSelector((s) => s.canvasV2.tool.invertScroll);
|
||||||
const onChangeInvertScroll = useCallback(
|
const onChangeInvertScroll = useCallback(
|
||||||
(e: ChangeEvent<HTMLInputElement>) => dispatch(invertScrollChanged(e.target.checked)),
|
(e: ChangeEvent<HTMLInputElement>) => dispatch(invertScrollChanged(e.target.checked)),
|
||||||
[dispatch]
|
[dispatch]
|
||||||
);
|
);
|
||||||
|
const onChangeClipToBbox = useCallback(
|
||||||
|
(e: ChangeEvent<HTMLInputElement>) => dispatch(clipToBboxChanged(e.target.checked)),
|
||||||
|
[dispatch]
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<Popover isLazy>
|
<Popover isLazy>
|
||||||
<PopoverTrigger>
|
<PopoverTrigger>
|
||||||
@ -38,6 +43,10 @@ const ControlLayersSettingsPopover = () => {
|
|||||||
<FormLabel flexGrow={1}>{t('unifiedCanvas.invertBrushSizeScrollDirection')}</FormLabel>
|
<FormLabel flexGrow={1}>{t('unifiedCanvas.invertBrushSizeScrollDirection')}</FormLabel>
|
||||||
<Checkbox isChecked={invertScroll} onChange={onChangeInvertScroll} />
|
<Checkbox isChecked={invertScroll} onChange={onChangeInvertScroll} />
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
<FormControl w="full">
|
||||||
|
<FormLabel flexGrow={1}>{t('unifiedCanvas.clipToBbox')}</FormLabel>
|
||||||
|
<Checkbox isChecked={clipToBbox} onChange={onChangeClipToBbox} />
|
||||||
|
</FormControl>
|
||||||
</Flex>
|
</Flex>
|
||||||
</PopoverBody>
|
</PopoverBody>
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
|
@ -53,6 +53,7 @@ type Arg = {
|
|||||||
setSpaceKey: (val: boolean) => void;
|
setSpaceKey: (val: boolean) => void;
|
||||||
getDocument: () => CanvasV2State['document'];
|
getDocument: () => CanvasV2State['document'];
|
||||||
getBbox: () => CanvasV2State['bbox'];
|
getBbox: () => CanvasV2State['bbox'];
|
||||||
|
getSettings: () => CanvasV2State['settings'];
|
||||||
onBrushLineAdded: (arg: BrushLineAddedArg, entityType: CanvasEntity['type']) => void;
|
onBrushLineAdded: (arg: BrushLineAddedArg, entityType: CanvasEntity['type']) => void;
|
||||||
onEraserLineAdded: (arg: EraserLineAddedArg, entityType: CanvasEntity['type']) => void;
|
onEraserLineAdded: (arg: EraserLineAddedArg, entityType: CanvasEntity['type']) => void;
|
||||||
onPointAddedToLine: (arg: PointAddedToLineArg, entityType: CanvasEntity['type']) => void;
|
onPointAddedToLine: (arg: PointAddedToLineArg, entityType: CanvasEntity['type']) => void;
|
||||||
@ -155,6 +156,7 @@ export const setStageEventHandlers = ({
|
|||||||
setSpaceKey,
|
setSpaceKey,
|
||||||
getDocument,
|
getDocument,
|
||||||
getBbox,
|
getBbox,
|
||||||
|
getSettings,
|
||||||
onBrushLineAdded,
|
onBrushLineAdded,
|
||||||
onEraserLineAdded,
|
onEraserLineAdded,
|
||||||
onPointAddedToLine,
|
onPointAddedToLine,
|
||||||
@ -203,6 +205,17 @@ export const setStageEventHandlers = ({
|
|||||||
|
|
||||||
if (toolState.selected === 'brush') {
|
if (toolState.selected === 'brush') {
|
||||||
const bbox = getBbox();
|
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) {
|
if (e.evt.shiftKey) {
|
||||||
const lastAddedPoint = getLastAddedPoint();
|
const lastAddedPoint = getLastAddedPoint();
|
||||||
// Create a straight line if holding shift
|
// Create a straight line if holding shift
|
||||||
@ -218,12 +231,7 @@ export const setStageEventHandlers = ({
|
|||||||
],
|
],
|
||||||
color: getCurrentFill(),
|
color: getCurrentFill(),
|
||||||
width: toolState.brush.width,
|
width: toolState.brush.width,
|
||||||
clip: {
|
clip,
|
||||||
x: bbox.x,
|
|
||||||
y: bbox.y,
|
|
||||||
width: bbox.width,
|
|
||||||
height: bbox.height,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
selectedEntity.type
|
selectedEntity.type
|
||||||
);
|
);
|
||||||
@ -240,12 +248,7 @@ export const setStageEventHandlers = ({
|
|||||||
],
|
],
|
||||||
color: getCurrentFill(),
|
color: getCurrentFill(),
|
||||||
width: toolState.brush.width,
|
width: toolState.brush.width,
|
||||||
clip: {
|
clip,
|
||||||
x: bbox.x,
|
|
||||||
y: bbox.y,
|
|
||||||
width: bbox.width,
|
|
||||||
height: bbox.height,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
selectedEntity.type
|
selectedEntity.type
|
||||||
);
|
);
|
||||||
@ -255,6 +258,16 @@ export const setStageEventHandlers = ({
|
|||||||
|
|
||||||
if (toolState.selected === 'eraser') {
|
if (toolState.selected === 'eraser') {
|
||||||
const bbox = getBbox();
|
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) {
|
if (e.evt.shiftKey) {
|
||||||
// Create a straight line if holding shift
|
// Create a straight line if holding shift
|
||||||
const lastAddedPoint = getLastAddedPoint();
|
const lastAddedPoint = getLastAddedPoint();
|
||||||
@ -269,12 +282,7 @@ export const setStageEventHandlers = ({
|
|||||||
pos.y - selectedEntity.y,
|
pos.y - selectedEntity.y,
|
||||||
],
|
],
|
||||||
width: toolState.eraser.width,
|
width: toolState.eraser.width,
|
||||||
clip: {
|
clip,
|
||||||
x: bbox.x,
|
|
||||||
y: bbox.y,
|
|
||||||
width: bbox.width,
|
|
||||||
height: bbox.height,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
selectedEntity.type
|
selectedEntity.type
|
||||||
);
|
);
|
||||||
@ -290,12 +298,7 @@ export const setStageEventHandlers = ({
|
|||||||
pos.y - selectedEntity.y,
|
pos.y - selectedEntity.y,
|
||||||
],
|
],
|
||||||
width: toolState.eraser.width,
|
width: toolState.eraser.width,
|
||||||
clip: {
|
clip,
|
||||||
x: bbox.x,
|
|
||||||
y: bbox.y,
|
|
||||||
width: bbox.width,
|
|
||||||
height: bbox.height,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
selectedEntity.type
|
selectedEntity.type
|
||||||
);
|
);
|
||||||
@ -402,6 +405,16 @@ export const setStageEventHandlers = ({
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const bbox = getBbox();
|
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
|
// Start a new line
|
||||||
onBrushLineAdded(
|
onBrushLineAdded(
|
||||||
{
|
{
|
||||||
@ -414,12 +427,7 @@ export const setStageEventHandlers = ({
|
|||||||
],
|
],
|
||||||
width: toolState.brush.width,
|
width: toolState.brush.width,
|
||||||
color: getCurrentFill(),
|
color: getCurrentFill(),
|
||||||
clip: {
|
clip,
|
||||||
x: bbox.x,
|
|
||||||
y: bbox.y,
|
|
||||||
width: bbox.width,
|
|
||||||
height: bbox.height,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
selectedEntity.type
|
selectedEntity.type
|
||||||
);
|
);
|
||||||
@ -441,6 +449,16 @@ export const setStageEventHandlers = ({
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const bbox = getBbox();
|
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
|
// Start a new line
|
||||||
onEraserLineAdded(
|
onEraserLineAdded(
|
||||||
{
|
{
|
||||||
@ -452,12 +470,7 @@ export const setStageEventHandlers = ({
|
|||||||
pos.y - selectedEntity.y,
|
pos.y - selectedEntity.y,
|
||||||
],
|
],
|
||||||
width: toolState.eraser.width,
|
width: toolState.eraser.width,
|
||||||
clip: {
|
clip,
|
||||||
x: bbox.x,
|
|
||||||
y: bbox.y,
|
|
||||||
width: bbox.width,
|
|
||||||
height: bbox.height,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
selectedEntity.type
|
selectedEntity.type
|
||||||
);
|
);
|
||||||
|
@ -33,8 +33,6 @@ const getControlAdapter = (manager: KonvaNodeManager, entity: ControlAdapterEnti
|
|||||||
listening: false,
|
listening: false,
|
||||||
});
|
});
|
||||||
const konvaObjectGroup = createObjectGroup(konvaLayer, CA_LAYER_OBJECT_GROUP_NAME);
|
const konvaObjectGroup = createObjectGroup(konvaLayer, CA_LAYER_OBJECT_GROUP_NAME);
|
||||||
konvaLayer.add(konvaObjectGroup);
|
|
||||||
manager.stage.add(konvaLayer);
|
|
||||||
return manager.add(entity.id, konvaLayer, konvaObjectGroup);
|
return manager.add(entity.id, konvaLayer, konvaObjectGroup);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3,8 +3,8 @@ import type { Store } from '@reduxjs/toolkit';
|
|||||||
import { logger } from 'app/logging/logger';
|
import { logger } from 'app/logging/logger';
|
||||||
import { $isDebugging } from 'app/store/nanostores/isDebugging';
|
import { $isDebugging } from 'app/store/nanostores/isDebugging';
|
||||||
import type { RootState } from 'app/store/store';
|
import type { RootState } from 'app/store/store';
|
||||||
import { KonvaNodeManager } from 'features/controlLayers/konva/nodeManager';
|
|
||||||
import { setStageEventHandlers } from 'features/controlLayers/konva/events';
|
import { setStageEventHandlers } from 'features/controlLayers/konva/events';
|
||||||
|
import { KonvaNodeManager } from 'features/controlLayers/konva/nodeManager';
|
||||||
import { arrangeEntities } from 'features/controlLayers/konva/renderers/arrange';
|
import { arrangeEntities } from 'features/controlLayers/konva/renderers/arrange';
|
||||||
import { renderBackgroundLayer } from 'features/controlLayers/konva/renderers/background';
|
import { renderBackgroundLayer } from 'features/controlLayers/konva/renderers/background';
|
||||||
import { updateBboxes } from 'features/controlLayers/konva/renderers/bbox';
|
import { updateBboxes } from 'features/controlLayers/konva/renderers/bbox';
|
||||||
@ -209,6 +209,7 @@ export const initializeRenderer = (
|
|||||||
const getBbox = () => getState().canvasV2.bbox;
|
const getBbox = () => getState().canvasV2.bbox;
|
||||||
const getDocument = () => getState().canvasV2.document;
|
const getDocument = () => getState().canvasV2.document;
|
||||||
const getToolState = () => getState().canvasV2.tool;
|
const getToolState = () => getState().canvasV2.tool;
|
||||||
|
const getSettings = () => getState().canvasV2.settings;
|
||||||
|
|
||||||
// Read-write state, ephemeral interaction state
|
// Read-write state, ephemeral interaction state
|
||||||
let isDrawing = false;
|
let isDrawing = false;
|
||||||
@ -268,6 +269,7 @@ export const initializeRenderer = (
|
|||||||
setStageAttrs: $stageAttrs.set,
|
setStageAttrs: $stageAttrs.set,
|
||||||
getDocument,
|
getDocument,
|
||||||
getBbox,
|
getBbox,
|
||||||
|
getSettings,
|
||||||
onBrushLineAdded,
|
onBrushLineAdded,
|
||||||
onEraserLineAdded,
|
onEraserLineAdded,
|
||||||
onPointAddedToLine,
|
onPointAddedToLine,
|
||||||
|
@ -184,6 +184,7 @@ export const {
|
|||||||
allEntitiesDeleted,
|
allEntitiesDeleted,
|
||||||
scaledBboxChanged,
|
scaledBboxChanged,
|
||||||
bboxScaleMethodChanged,
|
bboxScaleMethodChanged,
|
||||||
|
clipToBboxChanged,
|
||||||
// layers
|
// layers
|
||||||
layerAdded,
|
layerAdded,
|
||||||
layerRecalled,
|
layerRecalled,
|
||||||
|
@ -5,4 +5,7 @@ export const settingsReducers = {
|
|||||||
maskOpacityChanged: (state, action: PayloadAction<number>) => {
|
maskOpacityChanged: (state, action: PayloadAction<number>) => {
|
||||||
state.settings.maskOpacity = action.payload;
|
state.settings.maskOpacity = action.payload;
|
||||||
},
|
},
|
||||||
|
clipToBboxChanged: (state, action: PayloadAction<boolean>) => {
|
||||||
|
state.settings.clipToBbox = action.payload;
|
||||||
|
},
|
||||||
} satisfies SliceCaseReducers<CanvasV2State>;
|
} satisfies SliceCaseReducers<CanvasV2State>;
|
||||||
|
Loading…
Reference in New Issue
Block a user