mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-02-03 18:15:19 -05:00
feat(ui): show only raster layers while staging
This is expose as a setting int he settings popover. On by default for distraction-free staging.
This commit is contained in:
committed by
Kent Keirsey
parent
4f8782f616
commit
ed7cfa73e4
@@ -1871,7 +1871,8 @@
|
||||
"preserveMask": {
|
||||
"label": "Preserve Masked Region",
|
||||
"alert": "Preserving Masked Region"
|
||||
}
|
||||
},
|
||||
"showOnlyRasterLayersWhileStaging": "Show Only Raster Layers While Staging"
|
||||
},
|
||||
"HUD": {
|
||||
"bbox": "Bbox",
|
||||
|
||||
@@ -22,6 +22,7 @@ import { CanvasSettingsOutputOnlyMaskedRegionsCheckbox } from 'features/controlL
|
||||
import { CanvasSettingsPreserveMaskCheckbox } from 'features/controlLayers/components/Settings/CanvasSettingsPreserveMaskCheckbox';
|
||||
import { CanvasSettingsRecalculateRectsButton } from 'features/controlLayers/components/Settings/CanvasSettingsRecalculateRectsButton';
|
||||
import { CanvasSettingsShowHUDSwitch } from 'features/controlLayers/components/Settings/CanvasSettingsShowHUDSwitch';
|
||||
import { CanvasSettingsShowOnlyRasterLayersWhileStagingSwitch } from 'features/controlLayers/components/Settings/CanvasSettingsShowOnlyRasterLayersWhileStagingSwitch';
|
||||
import { CanvasSettingsShowProgressOnCanvas } from 'features/controlLayers/components/Settings/CanvasSettingsShowProgressOnCanvasSwitch';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -45,6 +46,7 @@ export const CanvasSettingsPopover = memo(() => {
|
||||
<CanvasSettingsOutputOnlyMaskedRegionsCheckbox />
|
||||
<CanvasSettingsSnapToGridCheckbox />
|
||||
<CanvasSettingsShowProgressOnCanvas />
|
||||
<CanvasSettingsShowOnlyRasterLayersWhileStagingSwitch />
|
||||
<CanvasSettingsDynamicGridSwitch />
|
||||
<CanvasSettingsBboxOverlaySwitch />
|
||||
<CanvasSettingsShowHUDSwitch />
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { FormControl, FormLabel, Switch } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import {
|
||||
selectShowOnlyRasterLayersWhileStaging,
|
||||
settingsShowOnlyRasterLayersWhileStagingToggled,
|
||||
} from 'features/controlLayers/store/canvasSettingsSlice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export const CanvasSettingsShowOnlyRasterLayersWhileStagingSwitch = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const showOnlyRasterLayersWhileStaging = useAppSelector(selectShowOnlyRasterLayersWhileStaging);
|
||||
const onChange = useCallback(() => {
|
||||
dispatch(settingsShowOnlyRasterLayersWhileStagingToggled());
|
||||
}, [dispatch]);
|
||||
|
||||
return (
|
||||
<FormControl>
|
||||
<FormLabel m={0} flexGrow={1}>
|
||||
{t('controlLayers.settings.showOnlyRasterLayersWhileStaging')}
|
||||
</FormLabel>
|
||||
<Switch size="sm" isChecked={showOnlyRasterLayersWhileStaging} onChange={onChange} />
|
||||
</FormControl>
|
||||
);
|
||||
});
|
||||
|
||||
CanvasSettingsShowOnlyRasterLayersWhileStagingSwitch.displayName =
|
||||
'CanvasSettingsShowOnlyRasterLayersWhileStagingSwitch';
|
||||
@@ -1,4 +1,6 @@
|
||||
import type { Selector } from '@reduxjs/toolkit';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import type { RootState } from 'app/store/store';
|
||||
import type { SerializableObject } from 'common/types';
|
||||
import { deepClone } from 'common/util/deepClone';
|
||||
import type { CanvasEntityBufferObjectRenderer } from 'features/controlLayers/konva/CanvasEntity/CanvasEntityBufferObjectRenderer';
|
||||
@@ -7,7 +9,7 @@ import type { CanvasEntityObjectRenderer } from 'features/controlLayers/konva/Ca
|
||||
import type { CanvasEntityTransformer } from 'features/controlLayers/konva/CanvasEntity/CanvasEntityTransformer';
|
||||
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
||||
import { CanvasModuleBase } from 'features/controlLayers/konva/CanvasModuleBase';
|
||||
import { getIsHiddenSelector, selectCanvasSlice, selectEntity } from 'features/controlLayers/store/selectors';
|
||||
import { buildEntityIsHiddenSelector, selectCanvasSlice, selectEntity } from 'features/controlLayers/store/selectors';
|
||||
import type { CanvasEntityIdentifier, CanvasRenderableEntityState, Rect } from 'features/controlLayers/store/types';
|
||||
import Konva from 'konva';
|
||||
import { atom, computed } from 'nanostores';
|
||||
@@ -73,6 +75,8 @@ export abstract class CanvasEntityAdapterBase<
|
||||
*/
|
||||
abstract getHashableState: () => SerializableObject;
|
||||
|
||||
private _selectIsHidden: Selector<RootState, boolean> | null = null;
|
||||
|
||||
/**
|
||||
* The Konva nodes that make up the entity adapter:
|
||||
* - A Konva.Layer to hold the everything
|
||||
@@ -149,13 +153,7 @@ export abstract class CanvasEntityAdapterBase<
|
||||
* - The entity's opacity/visibility
|
||||
* - The entity's transformer interaction state, which will show/hide the entity's selection outline
|
||||
*/
|
||||
this.subscriptions.add(
|
||||
this.manager.stateApi.createStoreSubscription(getIsHiddenSelector(this.entityIdentifier.type), (isHidden) => {
|
||||
this.$isHidden.set(isHidden);
|
||||
this.syncOpacity();
|
||||
this.transformer.syncInteractionState();
|
||||
})
|
||||
);
|
||||
this.subscriptions.add(this.manager.stateApi.createStoreSubscription(this.selectIsHidden, this.syncVisibility));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -166,12 +164,21 @@ export abstract class CanvasEntityAdapterBase<
|
||||
(canvas) => selectEntity(canvas, this.entityIdentifier) as T | undefined
|
||||
);
|
||||
|
||||
// This must be a getter because the selector depends on the entityIdentifier, which is set in the constructor.
|
||||
get selectIsHidden() {
|
||||
if (!this._selectIsHidden) {
|
||||
this._selectIsHidden = buildEntityIsHiddenSelector(this.entityIdentifier);
|
||||
}
|
||||
return this._selectIsHidden;
|
||||
}
|
||||
|
||||
initialize = async () => {
|
||||
this.log.debug('Initializing module');
|
||||
await this.sync(this.manager.stateApi.runSelector(this.selectState), undefined);
|
||||
this.transformer.initialize();
|
||||
await this.renderer.initialize();
|
||||
this.syncZIndices();
|
||||
this.syncVisibility();
|
||||
};
|
||||
|
||||
syncZIndices = () => {
|
||||
@@ -224,6 +231,12 @@ export abstract class CanvasEntityAdapterBase<
|
||||
this.renderer.updateOpacity();
|
||||
};
|
||||
|
||||
syncVisibility = () => {
|
||||
const isHidden = this.manager.stateApi.runSelector(this.selectIsHidden);
|
||||
this.$isHidden.set(isHidden);
|
||||
this.konva.layer.visible(!isHidden);
|
||||
};
|
||||
|
||||
/**
|
||||
* Synchronizes the entity's locked state with the canvas.
|
||||
*/
|
||||
|
||||
@@ -247,9 +247,7 @@ export class CanvasEntityObjectRenderer extends CanvasModuleBase {
|
||||
updateOpacity = () => {
|
||||
this.log.trace('Updating opacity');
|
||||
|
||||
const opacity = this.manager.stateApi.getIsTypeHidden(this.parent.entityIdentifier.type)
|
||||
? 0
|
||||
: this.parent.state.opacity;
|
||||
const opacity = this.parent.state.opacity;
|
||||
|
||||
if (this.konva.compositing) {
|
||||
this.konva.compositing.group.opacity(opacity);
|
||||
|
||||
@@ -72,6 +72,10 @@ type CanvasSettingsState = {
|
||||
* Whether to preserve the masked region instead of inpainting it.
|
||||
*/
|
||||
preserveMask: boolean;
|
||||
/**
|
||||
* Whether to show only raster layers while staging.
|
||||
*/
|
||||
showOnlyRasterLayersWhileStaging: boolean;
|
||||
};
|
||||
|
||||
const initialState: CanvasSettingsState = {
|
||||
@@ -90,6 +94,7 @@ const initialState: CanvasSettingsState = {
|
||||
showProgressOnCanvas: true,
|
||||
bboxOverlay: false,
|
||||
preserveMask: false,
|
||||
showOnlyRasterLayersWhileStaging: true,
|
||||
};
|
||||
|
||||
export const canvasSettingsSlice = createSlice({
|
||||
@@ -141,6 +146,9 @@ export const canvasSettingsSlice = createSlice({
|
||||
settingsPreserveMaskToggled: (state) => {
|
||||
state.preserveMask = !state.preserveMask;
|
||||
},
|
||||
settingsShowOnlyRasterLayersWhileStagingToggled: (state) => {
|
||||
state.showOnlyRasterLayersWhileStaging = !state.showOnlyRasterLayersWhileStaging;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -160,6 +168,7 @@ export const {
|
||||
settingsShowProgressOnCanvasToggled,
|
||||
settingsBboxOverlayToggled,
|
||||
settingsPreserveMaskToggled,
|
||||
settingsShowOnlyRasterLayersWhileStagingToggled,
|
||||
} = canvasSettingsSlice.actions;
|
||||
|
||||
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
||||
@@ -192,3 +201,6 @@ export const selectSendToCanvas = createCanvasSettingsSelector((canvasSettings)
|
||||
export const selectShowProgressOnCanvas = createCanvasSettingsSelector(
|
||||
(canvasSettings) => canvasSettings.showProgressOnCanvas
|
||||
);
|
||||
export const selectShowOnlyRasterLayersWhileStaging = createCanvasSettingsSelector(
|
||||
(canvasSettings) => canvasSettings.showOnlyRasterLayersWhileStaging
|
||||
);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import type { RootState } from 'app/store/store';
|
||||
import { selectShowOnlyRasterLayersWhileStaging } from 'features/controlLayers/store/canvasSettingsSlice';
|
||||
import { selectIsStaging } from 'features/controlLayers/store/canvasStagingAreaSlice';
|
||||
import { selectParamsSlice } from 'features/controlLayers/store/paramsSlice';
|
||||
import type {
|
||||
CanvasControlLayerState,
|
||||
@@ -11,6 +13,7 @@ import type {
|
||||
CanvasRegionalGuidanceState,
|
||||
CanvasState,
|
||||
} from 'features/controlLayers/store/types';
|
||||
import { isRasterLayerEntityIdentifier } from 'features/controlLayers/store/types';
|
||||
import { getOptimalDimension } from 'features/parameters/util/optimalDimension';
|
||||
import { assert } from 'tsafe';
|
||||
|
||||
@@ -269,7 +272,7 @@ const selectRegionalGuidanceIsHidden = createSelector(selectCanvasSlice, (canvas
|
||||
/**
|
||||
* Returns the hidden selector for the given entity type.
|
||||
*/
|
||||
export const getIsHiddenSelector = (type: CanvasEntityType) => {
|
||||
const getSelectIsTypeHidden = (type: CanvasEntityType) => {
|
||||
switch (type) {
|
||||
case 'raster_layer':
|
||||
return selectRasterLayersIsHidden;
|
||||
@@ -284,6 +287,42 @@ export const getIsHiddenSelector = (type: CanvasEntityType) => {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Builds a selector taht selects if the entity is hidden.
|
||||
*/
|
||||
export const buildEntityIsHiddenSelector = (entityIdentifier: CanvasEntityIdentifier) => {
|
||||
const selectIsTypeHidden = getSelectIsTypeHidden(entityIdentifier.type);
|
||||
return createSelector(
|
||||
[selectCanvasSlice, selectIsTypeHidden, selectIsStaging, selectShowOnlyRasterLayersWhileStaging],
|
||||
(canvas, isTypeHidden, isStaging, showOnlyRasterLayersWhileStaging) => {
|
||||
const entity = selectEntityOrThrow(canvas, entityIdentifier);
|
||||
|
||||
// An entity is hidden if:
|
||||
// - The entity type is hidden
|
||||
// - The entity is disabled
|
||||
// - The entity is locked
|
||||
// - The entity is not a raster layer and we are staging and the option to show only raster layers is enabled
|
||||
|
||||
if (isTypeHidden) {
|
||||
return true;
|
||||
}
|
||||
if (!entity.isEnabled) {
|
||||
return true;
|
||||
}
|
||||
if (entity.isLocked) {
|
||||
return true;
|
||||
}
|
||||
if (isStaging && showOnlyRasterLayersWhileStaging) {
|
||||
// When staging, we only show raster layers. This allows the user to easily see how the new generation fits in
|
||||
// with the rest of the canvas without the masks and control layers getting in the way.
|
||||
return !isRasterLayerEntityIdentifier(entityIdentifier);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const selectWidth = createSelector(selectCanvasSlice, (canvas) => canvas.bbox.rect.width);
|
||||
export const selectHeight = createSelector(selectCanvasSlice, (canvas) => canvas.bbox.rect.height);
|
||||
export const selectAspectRatioID = createSelector(selectCanvasSlice, (canvas) => canvas.bbox.aspectRatio.id);
|
||||
|
||||
Reference in New Issue
Block a user