feat(ui): add alt+[ and alt+] hotkeys to cycle through layers

This commit is contained in:
psychedelicious
2024-09-01 19:16:51 +10:00
parent 75ecc56ca5
commit 420178c09f
4 changed files with 87 additions and 10 deletions

View File

@@ -10,6 +10,7 @@ import { CanvasToolbarScale } from 'features/controlLayers/components/Toolbar/Ca
import { CanvasManagerProviderGate } from 'features/controlLayers/contexts/CanvasManagerProviderGate';
import { useCanvasEntityQuickSwitch } from 'features/controlLayers/hooks/useCanvasEntityQuickSwitch';
import { useCanvasUndoRedo } from 'features/controlLayers/hooks/useCanvasUndoRedo';
import { useNextPrevEntityHotkeys } from 'features/controlLayers/hooks/useNextPrevEntity';
import { ToggleProgressButton } from 'features/gallery/components/ImageViewer/ToggleProgressButton';
import { ViewerToggle } from 'features/gallery/components/ImageViewer/ViewerToggleMenu';
import { memo } from 'react';
@@ -17,6 +18,7 @@ import { memo } from 'react';
export const CanvasToolbar = memo(() => {
useCanvasUndoRedo();
useCanvasEntityQuickSwitch();
useNextPrevEntityHotkeys();
return (
<CanvasManagerProviderGate>

View File

@@ -1,4 +1,3 @@
/* eslint-disable i18next/no-literal-string */
import { useAppSelector } from 'app/store/storeHooks';
import { useAssertSingleton } from 'common/hooks/useAssertSingleton';
import { canvasRedo, canvasUndo } from 'features/controlLayers/store/canvasSlice';

View File

@@ -0,0 +1,76 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { useAssertSingleton } from 'common/hooks/useAssertSingleton';
import { entitySelected } from 'features/controlLayers/store/canvasSlice';
import { selectAllEntities, selectCanvasSlice } from 'features/controlLayers/store/selectors';
import type { CanvasEntityState } from 'features/controlLayers/store/types';
import { getEntityIdentifier } from 'features/controlLayers/store/types';
import { useCallback } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
const selectNextEntityIdentifier = createMemoizedSelector(selectCanvasSlice, (canvas) => {
const selectedEntityIdentifier = canvas.selectedEntityIdentifier;
const allEntities = selectAllEntities(canvas);
let nextEntity: CanvasEntityState | null = null;
if (!selectedEntityIdentifier) {
nextEntity = allEntities[0] ?? null;
} else {
const selectedEntityIndex = allEntities.findIndex((entity) => entity.id === selectedEntityIdentifier.id);
nextEntity = allEntities[(selectedEntityIndex + 1) % allEntities.length] ?? null;
}
if (!nextEntity) {
return null;
}
return getEntityIdentifier(nextEntity);
});
const selectPrevEntityIdentifier = createMemoizedSelector(selectCanvasSlice, (canvas) => {
const selectedEntityIdentifier = canvas.selectedEntityIdentifier;
const allEntities = selectAllEntities(canvas);
let prevEntity: CanvasEntityState | null = null;
if (!selectedEntityIdentifier) {
prevEntity = allEntities[0] ?? null;
} else {
const selectedEntityIndex = allEntities.findIndex((entity) => entity.id === selectedEntityIdentifier.id);
prevEntity = allEntities[(selectedEntityIndex - 1 + allEntities.length) % allEntities.length] ?? null;
}
if (!prevEntity) {
return null;
}
return getEntityIdentifier(prevEntity);
});
export const useNextPrevEntityHotkeys = () => {
useAssertSingleton('useNextPrevEntityHotkeys');
const dispatch = useAppDispatch();
const nextEntityIdentifier = useAppSelector(selectNextEntityIdentifier);
const prevEntityIdentifier = useAppSelector(selectPrevEntityIdentifier);
const selectNextEntity = useCallback(() => {
if (nextEntityIdentifier) {
dispatch(entitySelected({ entityIdentifier: nextEntityIdentifier }));
}
}, [dispatch, nextEntityIdentifier]);
const selectPrevEntity = useCallback(() => {
if (prevEntityIdentifier) {
dispatch(entitySelected({ entityIdentifier: prevEntityIdentifier }));
}
}, [dispatch, prevEntityIdentifier]);
useHotkeys(
// “ === alt+[
['alt+[', '“'],
selectPrevEntity,
{ preventDefault: true, ignoreModifiers: true },
[selectPrevEntity]
);
useHotkeys(
// === alt+]
['alt+]', ''],
selectNextEntity,
{ preventDefault: true, ignoreModifiers: true },
[selectNextEntity]
);
};

View File

@@ -1,16 +1,16 @@
import { createSelector } from '@reduxjs/toolkit';
import type { RootState } from 'app/store/store';
import { selectParamsSlice } from 'features/controlLayers/store/paramsSlice';
import {
type CanvasControlLayerState,
type CanvasEntityIdentifier,
type CanvasEntityState,
type CanvasInpaintMaskState,
type CanvasRasterLayerState,
type CanvasRegionalGuidanceState,
type CanvasState,
isDrawableEntityType,
import type {
CanvasControlLayerState,
CanvasEntityIdentifier,
CanvasEntityState,
CanvasInpaintMaskState,
CanvasRasterLayerState,
CanvasRegionalGuidanceState,
CanvasState,
} from 'features/controlLayers/store/types';
import { isDrawableEntityType } from 'features/controlLayers/store/types';
import { getOptimalDimension } from 'features/parameters/util/optimalDimension';
import { assert } from 'tsafe';