mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-02-15 09:55:59 -05:00
77 lines
2.9 KiB
TypeScript
77 lines
2.9 KiB
TypeScript
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]
|
||
);
|
||
};
|