feat(ui): add snap & autosave to HUD

This commit is contained in:
psychedelicious
2024-09-08 19:38:25 +10:00
parent 44df59e9e9
commit 9709da901c
10 changed files with 129 additions and 45 deletions

View File

@@ -93,6 +93,7 @@
"copy": "Copy",
"copyError": "$t(gallery.copy) Error",
"on": "On",
"off": "Off",
"or": "or",
"checkpoint": "Checkpoint",
"communityLabel": "Community",
@@ -1819,6 +1820,12 @@
"8": "8px",
"64": "64px"
}
},
"HUD": {
"snapToGrid": "Snap",
"bbox": "Bbox",
"scaledBbox": "Scaled Bbox",
"autoSave": "Auto Save"
}
},
"upscaling": {

View File

@@ -0,0 +1,28 @@
import { Grid } from '@invoke-ai/ui-library';
import { CanvasHUDItemAutoSave } from 'features/controlLayers/components/HUD/CanvasHUDItemAutoSave';
import { CanvasHUDItemBbox } from 'features/controlLayers/components/HUD/CanvasHUDItemBbox';
import { CanvasHUDItemScaledBbox } from 'features/controlLayers/components/HUD/CanvasHUDItemScaledBbox';
import { CanvasHUDItemSnapToGrid } from 'features/controlLayers/components/HUD/CanvasHUDItemSnapToGrid';
import { memo } from 'react';
export const CanvasHUD = memo(() => {
return (
<Grid
bg="base.900"
borderBottomEndRadius="base"
p={2}
gap={2}
borderRadius="base"
templateColumns="1fr 1fr"
opacity={0.6}
minW={64}
>
<CanvasHUDItemBbox />
<CanvasHUDItemScaledBbox />
<CanvasHUDItemSnapToGrid />
<CanvasHUDItemAutoSave />
</Grid>
);
});
CanvasHUD.displayName = 'CanvasHUD';

View File

@@ -0,0 +1,17 @@
import { GridItem, Text } from '@invoke-ai/ui-library';
import { memo } from 'react';
export const CanvasHUDItem = memo(({ label, value }: { label: string; value: string | number }) => {
return (
<>
<GridItem>
<Text textAlign="end">{label}: </Text>
</GridItem>
<GridItem fontWeight="semibold">
<Text textAlign="end">{value}</Text>
</GridItem>
</>
);
});
CanvasHUDItem.displayName = 'CanvasHUDItem';

View File

@@ -0,0 +1,14 @@
import { useAppSelector } from 'app/store/storeHooks';
import { CanvasHUDItem } from 'features/controlLayers/components/HUD/CanvasHUDItem';
import { selectAutoSave } from 'features/controlLayers/store/canvasSettingsSlice';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
export const CanvasHUDItemAutoSave = memo(() => {
const { t } = useTranslation();
const autoSave = useAppSelector(selectAutoSave);
return <CanvasHUDItem label={t('controlLayers.HUD.autoSave')} value={autoSave ? t('common.on') : t('common.off')} />;
});
CanvasHUDItemAutoSave.displayName = 'CanvasHUDItemAutoSave';

View File

@@ -0,0 +1,17 @@
import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/store/storeHooks';
import { CanvasHUDItem } from 'features/controlLayers/components/HUD/CanvasHUDItem';
import { selectBbox } from 'features/controlLayers/store/selectors';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
const selectBboxRect = createSelector(selectBbox, (bbox) => bbox.rect);
export const CanvasHUDItemBbox = memo(() => {
const { t } = useTranslation();
const rect = useAppSelector(selectBboxRect);
return <CanvasHUDItem label={t('controlLayers.HUD.bbox')} value={`${rect.width}×${rect.height} px`} />;
});
CanvasHUDItemBbox.displayName = 'CanvasHUDItemBbox';

View File

@@ -0,0 +1,19 @@
import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/store/storeHooks';
import { CanvasHUDItem } from 'features/controlLayers/components/HUD/CanvasHUDItem';
import { selectBbox } from 'features/controlLayers/store/selectors';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
const selectScaledSize = createSelector(selectBbox, (bbox) => bbox.scaledSize);
export const CanvasHUDItemScaledBbox = memo(() => {
const { t } = useTranslation();
const scaledSize = useAppSelector(selectScaledSize);
return (
<CanvasHUDItem label={t('controlLayers.HUD.scaledBbox')} value={`${scaledSize.width}×${scaledSize.height} px`} />
);
});
CanvasHUDItemScaledBbox.displayName = 'CanvasHUDItemScaledBbox';

View File

@@ -0,0 +1,24 @@
import { useAppSelector } from 'app/store/storeHooks';
import { CanvasHUDItem } from 'features/controlLayers/components/HUD/CanvasHUDItem';
import { selectSnapToGrid } from 'features/controlLayers/store/canvasSettingsSlice';
import { memo, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
export const CanvasHUDItemSnapToGrid = memo(() => {
const { t } = useTranslation();
const snap = useAppSelector(selectSnapToGrid);
const snapString = useMemo(() => {
switch (snap) {
case 'off':
return t('controlLayers.settings.snapToGrid.off');
case '8':
return t('controlLayers.settings.snapToGrid.8');
case '64':
return t('controlLayers.settings.snapToGrid.64');
}
}, [snap, t]);
return <CanvasHUDItem label={t('controlLayers.HUD.snapToGrid')} value={snapString} />;
});
CanvasHUDItemSnapToGrid.displayName = 'CanvasHUDItemSnapToGrid';

View File

@@ -1,43 +0,0 @@
import { Grid, GridItem, Text } from '@invoke-ai/ui-library';
import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/store/storeHooks';
import { selectCanvasSlice } from 'features/controlLayers/store/selectors';
import { memo } from 'react';
const selectBbox = createSelector(selectCanvasSlice, (canvas) => canvas.bbox);
export const HeadsUpDisplay = memo(() => {
const bbox = useAppSelector(selectBbox);
return (
<Grid
bg="base.900"
borderBottomEndRadius="base"
p={2}
gap={2}
borderRadius="base"
templateColumns="auto auto"
opacity={0.6}
>
<HUDItem label="BBox" value={`${bbox.rect.width}×${bbox.rect.height} px`} />
<HUDItem label="Scaled BBox" value={`${bbox.scaledSize.width}×${bbox.scaledSize.height} px`} />
</Grid>
);
});
HeadsUpDisplay.displayName = 'HeadsUpDisplay';
const HUDItem = memo(({ label, value }: { label: string; value: string | number }) => {
return (
<>
<GridItem>
<Text textAlign="end">{label}: </Text>
</GridItem>
<GridItem fontWeight="semibold">
<Text>{value}</Text>
</GridItem>
</>
);
});
HUDItem.displayName = 'HUDItem';

View File

@@ -4,7 +4,7 @@ import { $socket } from 'app/hooks/useSocketIO';
import { logger } from 'app/logging/logger';
import { useAppStore } from 'app/store/nanostores/store';
import { useAppSelector } from 'app/store/storeHooks';
import { HeadsUpDisplay } from 'features/controlLayers/components/HeadsUpDisplay';
import { CanvasHUD } from 'features/controlLayers/components/HUD/CanvasHUD';
import { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
import { TRANSPARENCY_CHECKERBOARD_PATTERN_DATAURL } from 'features/controlLayers/konva/patterns/transparency-checkerboard-pattern';
import { getPrefixedId } from 'features/controlLayers/konva/util';
@@ -99,7 +99,7 @@ export const StageComponent = memo(() => {
/>
{showHUD && (
<Flex position="absolute" top={1} insetInlineStart={1} pointerEvents="none">
<HeadsUpDisplay />
<CanvasHUD />
</Flex>
)}
</Flex>

View File

@@ -156,6 +156,7 @@ export const selectCanvasSettingsSlice = (s: RootState) => s.canvasSettings;
const createCanvasSettingsSelector = <T>(selector: Selector<CanvasSettingsState, T>) =>
createSelector(selectCanvasSettingsSlice, selector);
export const selectAutoSave = createCanvasSettingsSelector((settings) => settings.autoSave);
export const selectDynamicGrid = createCanvasSettingsSelector((settings) => settings.dynamicGrid);
export const selectShowHUD = createCanvasSettingsSelector((settings) => settings.showHUD);
export const selectAutoPreviewFilter = createCanvasSettingsSelector((settings) => settings.autoPreviewFilter);