mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): restore transparency effect for control layers
This commit is contained in:
parent
c7913cbbbb
commit
04f56aab82
@ -1703,6 +1703,8 @@
|
|||||||
"filter": "Filter",
|
"filter": "Filter",
|
||||||
"convertToControlLayer": "Convert to Control Layer",
|
"convertToControlLayer": "Convert to Control Layer",
|
||||||
"convertToRasterLayer": "Convert to Raster Layer",
|
"convertToRasterLayer": "Convert to Raster Layer",
|
||||||
|
"enableTransparencyEffect": "Enable Transparency Effect",
|
||||||
|
"disableTransparencyEffect": "Disable Transparency Effect",
|
||||||
"fill": {
|
"fill": {
|
||||||
"fillStyle": "Fill Style",
|
"fillStyle": "Fill Style",
|
||||||
"solid": "Solid",
|
"solid": "Solid",
|
||||||
|
@ -4,6 +4,7 @@ import { CanvasEntityMenuItemsDelete } from 'features/controlLayers/components/c
|
|||||||
import { CanvasEntityMenuItemsFilter } from 'features/controlLayers/components/common/CanvasEntityMenuItemsFilter';
|
import { CanvasEntityMenuItemsFilter } from 'features/controlLayers/components/common/CanvasEntityMenuItemsFilter';
|
||||||
import { CanvasEntityMenuItemsReset } from 'features/controlLayers/components/common/CanvasEntityMenuItemsReset';
|
import { CanvasEntityMenuItemsReset } from 'features/controlLayers/components/common/CanvasEntityMenuItemsReset';
|
||||||
import { ControlLayerMenuItemsControlToRaster } from 'features/controlLayers/components/ControlLayer/ControlLayerMenuItemsControlToRaster';
|
import { ControlLayerMenuItemsControlToRaster } from 'features/controlLayers/components/ControlLayer/ControlLayerMenuItemsControlToRaster';
|
||||||
|
import { ControlLayerMenuItemsTransparencyEffect } from 'features/controlLayers/components/ControlLayer/ControlLayerMenuItemsTransparencyEffect';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
|
||||||
export const ControlLayerMenuItems = memo(() => {
|
export const ControlLayerMenuItems = memo(() => {
|
||||||
@ -11,6 +12,7 @@ export const ControlLayerMenuItems = memo(() => {
|
|||||||
<>
|
<>
|
||||||
<CanvasEntityMenuItemsFilter />
|
<CanvasEntityMenuItemsFilter />
|
||||||
<ControlLayerMenuItemsControlToRaster />
|
<ControlLayerMenuItemsControlToRaster />
|
||||||
|
<ControlLayerMenuItemsTransparencyEffect />
|
||||||
<MenuDivider />
|
<MenuDivider />
|
||||||
<CanvasEntityMenuItemsArrange />
|
<CanvasEntityMenuItemsArrange />
|
||||||
<MenuDivider />
|
<MenuDivider />
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
import { MenuItem } from '@invoke-ai/ui-library';
|
||||||
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
|
import { useEntityIdentifierContext } from 'features/controlLayers/contexts/EntityIdentifierContext';
|
||||||
|
import {
|
||||||
|
controlLayerWithTransparencyEffectToggled,
|
||||||
|
selectCanvasV2Slice,
|
||||||
|
} from 'features/controlLayers/store/canvasV2Slice';
|
||||||
|
import { selectControlLayerOrThrow } from 'features/controlLayers/store/controlLayersReducers';
|
||||||
|
import { memo, useCallback, useMemo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { PiDropHalfBold } from 'react-icons/pi';
|
||||||
|
|
||||||
|
export const ControlLayerMenuItemsTransparencyEffect = memo(() => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const entityIdentifier = useEntityIdentifierContext();
|
||||||
|
const selectWithTransparencyEffect = useMemo(
|
||||||
|
() =>
|
||||||
|
createSelector(selectCanvasV2Slice, (canvasV2) => {
|
||||||
|
const entity = selectControlLayerOrThrow(canvasV2, entityIdentifier.id);
|
||||||
|
return entity.withTransparencyEffect;
|
||||||
|
}),
|
||||||
|
[entityIdentifier.id]
|
||||||
|
);
|
||||||
|
const withTransparencyEffect = useAppSelector(selectWithTransparencyEffect);
|
||||||
|
const onToggle = useCallback(() => {
|
||||||
|
dispatch(controlLayerWithTransparencyEffectToggled({ id: entityIdentifier.id }));
|
||||||
|
}, [dispatch, entityIdentifier]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MenuItem onClick={onToggle} icon={<PiDropHalfBold />}>
|
||||||
|
{withTransparencyEffect
|
||||||
|
? t('controlLayers.disableTransparencyEffect')
|
||||||
|
: t('controlLayers.enableTransparencyEffect')}
|
||||||
|
</MenuItem>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
ControlLayerMenuItemsTransparencyEffect.displayName = 'ControlLayerMenuItemsTransparencyEffect';
|
@ -100,6 +100,12 @@ export class CanvasLayerAdapter {
|
|||||||
if (this.isFirstRender || opacity !== this.state.opacity) {
|
if (this.isFirstRender || opacity !== this.state.opacity) {
|
||||||
this.renderer.updateOpacity(opacity);
|
this.renderer.updateOpacity(opacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (state.type === 'control_layer' && this.state.type === 'control_layer') {
|
||||||
|
if (this.isFirstRender || state.withTransparencyEffect !== this.state.withTransparencyEffect) {
|
||||||
|
this.renderer.updateTransparencyEffect(state.withTransparencyEffect);
|
||||||
|
}
|
||||||
|
}
|
||||||
// this.transformer.syncInteractionState();
|
// this.transformer.syncInteractionState();
|
||||||
|
|
||||||
if (this.isFirstRender) {
|
if (this.isFirstRender) {
|
||||||
@ -129,12 +135,6 @@ export class CanvasLayerAdapter {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
updateOpacity = (arg?: { opacity: number }) => {
|
|
||||||
this.log.trace('Updating opacity');
|
|
||||||
const opacity = get(arg, 'opacity', this.state.opacity);
|
|
||||||
this.renderer.konva.objectGroup.opacity(opacity);
|
|
||||||
};
|
|
||||||
|
|
||||||
repr = () => {
|
repr = () => {
|
||||||
return {
|
return {
|
||||||
id: this.id,
|
id: this.id,
|
||||||
|
@ -7,6 +7,7 @@ import type { CanvasLayerAdapter } from 'features/controlLayers/konva/CanvasLaye
|
|||||||
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
||||||
import type { CanvasMaskAdapter } from 'features/controlLayers/konva/CanvasMaskAdapter';
|
import type { CanvasMaskAdapter } from 'features/controlLayers/konva/CanvasMaskAdapter';
|
||||||
import { CanvasRectRenderer } from 'features/controlLayers/konva/CanvasRect';
|
import { CanvasRectRenderer } from 'features/controlLayers/konva/CanvasRect';
|
||||||
|
import { LightnessToAlphaFilter } from 'features/controlLayers/konva/filters';
|
||||||
import { getPatternSVG } from 'features/controlLayers/konva/patterns/getPatternSVG';
|
import { getPatternSVG } from 'features/controlLayers/konva/patterns/getPatternSVG';
|
||||||
import { getPrefixedId, konvaNodeToBlob, konvaNodeToImageData, previewBlob } from 'features/controlLayers/konva/util';
|
import { getPrefixedId, konvaNodeToBlob, konvaNodeToImageData, previewBlob } from 'features/controlLayers/konva/util';
|
||||||
import type {
|
import type {
|
||||||
@ -203,6 +204,11 @@ export class CanvasObjectRenderer {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
updateTransparencyEffect = (withTransparencyEffect: boolean) => {
|
||||||
|
const filters = withTransparencyEffect ? [LightnessToAlphaFilter] : [];
|
||||||
|
this.konva.objectGroup.filters(filters);
|
||||||
|
};
|
||||||
|
|
||||||
updateCompositingRectFill = (fill: Fill) => {
|
updateCompositingRectFill = (fill: Fill) => {
|
||||||
this.log.trace('Updating compositing rect fill');
|
this.log.trace('Updating compositing rect fill');
|
||||||
assert(this.konva.compositing, 'Missing compositing rect');
|
assert(this.konva.compositing, 'Missing compositing rect');
|
||||||
|
@ -584,6 +584,7 @@ export const {
|
|||||||
controlLayerControlModeChanged,
|
controlLayerControlModeChanged,
|
||||||
controlLayerWeightChanged,
|
controlLayerWeightChanged,
|
||||||
controlLayerBeginEndStepPctChanged,
|
controlLayerBeginEndStepPctChanged,
|
||||||
|
controlLayerWithTransparencyEffectToggled,
|
||||||
// IP Adapters
|
// IP Adapters
|
||||||
ipaAdded,
|
ipaAdded,
|
||||||
ipaRecalled,
|
ipaRecalled,
|
||||||
|
@ -36,6 +36,7 @@ export const controlLayersReducers = {
|
|||||||
name: null,
|
name: null,
|
||||||
type: 'control_layer',
|
type: 'control_layer',
|
||||||
isEnabled: true,
|
isEnabled: true,
|
||||||
|
withTransparencyEffect: true,
|
||||||
objects: [],
|
objects: [],
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
position: { x: 0, y: 0 },
|
position: { x: 0, y: 0 },
|
||||||
@ -70,7 +71,7 @@ export const controlLayersReducers = {
|
|||||||
|
|
||||||
// Convert the raster layer to control layer
|
// Convert the raster layer to control layer
|
||||||
const rasterLayerState: CanvasRasterLayerState = {
|
const rasterLayerState: CanvasRasterLayerState = {
|
||||||
...omit(deepClone(layer), ['type', 'controlAdapter']),
|
...omit(deepClone(layer), ['type', 'controlAdapter', 'withTransparencyEffect']),
|
||||||
id: newId,
|
id: newId,
|
||||||
type: 'raster_layer',
|
type: 'raster_layer',
|
||||||
};
|
};
|
||||||
@ -151,4 +152,12 @@ export const controlLayersReducers = {
|
|||||||
}
|
}
|
||||||
layer.controlAdapter.beginEndStepPct = beginEndStepPct;
|
layer.controlAdapter.beginEndStepPct = beginEndStepPct;
|
||||||
},
|
},
|
||||||
|
controlLayerWithTransparencyEffectToggled: (state, action: PayloadAction<{ id: string }>) => {
|
||||||
|
const { id } = action.payload;
|
||||||
|
const layer = selectControlLayer(state, id);
|
||||||
|
if (!layer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
layer.withTransparencyEffect = !layer.withTransparencyEffect;
|
||||||
|
},
|
||||||
} satisfies SliceCaseReducers<CanvasV2State>;
|
} satisfies SliceCaseReducers<CanvasV2State>;
|
||||||
|
@ -89,6 +89,7 @@ export const rasterLayersReducers = {
|
|||||||
id: newId,
|
id: newId,
|
||||||
type: 'control_layer',
|
type: 'control_layer',
|
||||||
controlAdapter,
|
controlAdapter,
|
||||||
|
withTransparencyEffect: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Remove the raster layer
|
// Remove the raster layer
|
||||||
|
@ -559,14 +559,14 @@ const zCanvasRectState = z.object({
|
|||||||
});
|
});
|
||||||
export type CanvasRectState = z.infer<typeof zCanvasRectState>;
|
export type CanvasRectState = z.infer<typeof zCanvasRectState>;
|
||||||
|
|
||||||
const zFilter = z.enum(['LightnessToAlphaFilter']);
|
const zLayerEffect = z.enum(['LightnessToAlphaFilter']);
|
||||||
export type Filter = z.infer<typeof zFilter>;
|
export type LayerEffect = z.infer<typeof zLayerEffect>;
|
||||||
|
|
||||||
const zCanvasImageState = z.object({
|
const zCanvasImageState = z.object({
|
||||||
id: zId,
|
id: zId,
|
||||||
type: z.literal('image'),
|
type: z.literal('image'),
|
||||||
image: zImageWithDims,
|
image: zImageWithDims,
|
||||||
filters: z.array(zFilter),
|
filters: z.array(zLayerEffect),
|
||||||
});
|
});
|
||||||
export type CanvasImageState = z.infer<typeof zCanvasImageState>;
|
export type CanvasImageState = z.infer<typeof zCanvasImageState>;
|
||||||
|
|
||||||
@ -699,7 +699,7 @@ const zCanvasControlAdapterStateBase = z.object({
|
|||||||
isEnabled: z.boolean(),
|
isEnabled: z.boolean(),
|
||||||
position: zCoordinate,
|
position: zCoordinate,
|
||||||
opacity: zOpacity,
|
opacity: zOpacity,
|
||||||
filters: z.array(zFilter),
|
filters: z.array(zLayerEffect),
|
||||||
weight: z.number().gte(-1).lte(2),
|
weight: z.number().gte(-1).lte(2),
|
||||||
imageObject: zCanvasImageState.nullable(),
|
imageObject: zCanvasImageState.nullable(),
|
||||||
processedImageObject: zCanvasImageState.nullable(),
|
processedImageObject: zCanvasImageState.nullable(),
|
||||||
@ -755,6 +755,7 @@ export type CanvasRasterLayerState = z.infer<typeof zCanvasRasterLayerState>;
|
|||||||
|
|
||||||
export const zCanvasControlLayerState = zCanvasRasterLayerState.extend({
|
export const zCanvasControlLayerState = zCanvasRasterLayerState.extend({
|
||||||
type: z.literal('control_layer'),
|
type: z.literal('control_layer'),
|
||||||
|
withTransparencyEffect: z.boolean(),
|
||||||
controlAdapter: z.discriminatedUnion('type', [zControlNetConfig, zT2IAdapterConfig]),
|
controlAdapter: z.discriminatedUnion('type', [zControlNetConfig, zT2IAdapterConfig]),
|
||||||
});
|
});
|
||||||
export type CanvasControlLayerState = z.infer<typeof zCanvasControlLayerState>;
|
export type CanvasControlLayerState = z.infer<typeof zCanvasControlLayerState>;
|
||||||
|
Loading…
Reference in New Issue
Block a user