feat(ui): global canvas hotkey interaction restrictions

This commit is contained in:
psychedelicious
2024-09-13 19:09:19 +10:00
parent 3aaaae4d1c
commit 73ea5cb42a
5 changed files with 45 additions and 22 deletions

View File

@@ -48,7 +48,9 @@ export const CanvasMainPanelContent = memo(() => {
alignItems="center"
justifyContent="center"
>
<CanvasToolbar />
<CanvasManagerProviderGate>
<CanvasToolbar />
</CanvasManagerProviderGate>
<ContextMenu<HTMLDivElement> renderMenu={renderMenu}>
{(ref) => (
<Flex

View File

@@ -8,7 +8,6 @@ import { CanvasToolbarFitBboxToLayersButton } from 'features/controlLayers/compo
import { CanvasToolbarResetViewButton } from 'features/controlLayers/components/Toolbar/CanvasToolbarResetViewButton';
import { CanvasToolbarSaveToGalleryButton } from 'features/controlLayers/components/Toolbar/CanvasToolbarSaveToGalleryButton';
import { CanvasToolbarScale } from 'features/controlLayers/components/Toolbar/CanvasToolbarScale';
import { CanvasManagerProviderGate } from 'features/controlLayers/contexts/CanvasManagerProviderGate';
import { useCanvasDeleteLayerHotkey } from 'features/controlLayers/hooks/useCanvasDeleteLayerHotkey';
import { useCanvasEntityQuickSwitchHotkey } from 'features/controlLayers/hooks/useCanvasEntityQuickSwitchHotkey';
import { useCanvasResetLayerHotkey } from 'features/controlLayers/hooks/useCanvasResetLayerHotkey';
@@ -24,21 +23,19 @@ export const CanvasToolbar = memo(() => {
useNextPrevEntityHotkeys();
return (
<CanvasManagerProviderGate>
<Flex w="full" gap={2} alignItems="center">
<ToolChooser />
<Spacer />
<ToolSettings />
<Spacer />
<CanvasToolbarScale />
<CanvasToolbarResetViewButton />
<Spacer />
<ToolColorPicker />
<CanvasToolbarFitBboxToLayersButton />
<CanvasToolbarSaveToGalleryButton />
<CanvasSettingsPopover />
</Flex>
</CanvasManagerProviderGate>
<Flex w="full" gap={2} alignItems="center">
<ToolChooser />
<Spacer />
<ToolSettings />
<Spacer />
<CanvasToolbarScale />
<CanvasToolbarResetViewButton />
<Spacer />
<ToolColorPicker />
<CanvasToolbarFitBboxToLayersButton />
<CanvasToolbarSaveToGalleryButton />
<CanvasSettingsPopover />
</Flex>
);
});

View File

@@ -1,5 +1,6 @@
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { useAssertSingleton } from 'common/hooks/useAssertSingleton';
import { useCanvasIsBusy } from 'features/controlLayers/hooks/useCanvasIsBusy';
import { entityDeleted } from 'features/controlLayers/store/canvasSlice';
import { selectIsStaging } from 'features/controlLayers/store/canvasStagingAreaSlice';
import { selectSelectedEntityIdentifier } from 'features/controlLayers/store/selectors';
@@ -11,6 +12,7 @@ export function useCanvasDeleteLayerHotkey() {
const dispatch = useAppDispatch();
const selectedEntityIdentifier = useAppSelector(selectSelectedEntityIdentifier);
const isStaging = useAppSelector(selectIsStaging);
const isBusy = useCanvasIsBusy();
const deleteSelectedLayer = useCallback(() => {
if (selectedEntityIdentifier === null) {
@@ -24,8 +26,9 @@ export function useCanvasDeleteLayerHotkey() {
[selectedEntityIdentifier, isStaging]
);
useHotkeys(['delete', 'backspace'], deleteSelectedLayer, { enabled: isDeleteEnabled }, [
useHotkeys(['delete', 'backspace'], deleteSelectedLayer, { enabled: isDeleteEnabled && !isBusy }, [
isDeleteEnabled,
isBusy,
deleteSelectedLayer,
]);
}

View File

@@ -1,9 +1,14 @@
import { useStore } from '@nanostores/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { useAssertSingleton } from 'common/hooks/useAssertSingleton';
import { useEntityAdapterSafe } from 'features/controlLayers/contexts/EntityAdapterContext';
import { useCanvasIsBusy } from 'features/controlLayers/hooks/useCanvasIsBusy';
import { entityReset } from 'features/controlLayers/store/canvasSlice';
import { selectCanvasSlice } from 'features/controlLayers/store/selectors';
import { isMaskEntityIdentifier } from 'features/controlLayers/store/types';
import type { ReadableAtom } from 'nanostores';
import { atom } from 'nanostores';
import { useCallback, useMemo } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
@@ -12,10 +17,15 @@ const selectSelectedEntityIdentifier = createMemoizedSelector(
(canvasState) => canvasState.selectedEntityIdentifier
);
const $fallbackFalse: ReadableAtom<boolean> = atom(false);
export function useCanvasResetLayerHotkey() {
useAssertSingleton(useCanvasResetLayerHotkey.name);
const dispatch = useAppDispatch();
const selectedEntityIdentifier = useAppSelector(selectSelectedEntityIdentifier);
const isBusy = useCanvasIsBusy();
const adapter = useEntityAdapterSafe(selectedEntityIdentifier);
const isInteractable = useStore(adapter?.$isInteractable ?? $fallbackFalse);
const resetSelectedLayer = useCallback(() => {
if (selectedEntityIdentifier === null) {
@@ -29,5 +39,10 @@ export function useCanvasResetLayerHotkey() {
[selectedEntityIdentifier]
);
useHotkeys('shift+c', resetSelectedLayer, { enabled: isResetEnabled }, [isResetEnabled, resetSelectedLayer]);
useHotkeys('shift+c', resetSelectedLayer, { enabled: isResetEnabled && !isBusy && isInteractable }, [
isResetEnabled,
isBusy,
isInteractable,
resetSelectedLayer,
]);
}

View File

@@ -1,5 +1,6 @@
import { useAppSelector } from 'app/store/storeHooks';
import { useAssertSingleton } from 'common/hooks/useAssertSingleton';
import { useCanvasIsBusy } from 'features/controlLayers/hooks/useCanvasIsBusy';
import { canvasRedo, canvasUndo } from 'features/controlLayers/store/canvasSlice';
import { selectCanvasMayRedo, selectCanvasMayUndo } from 'features/controlLayers/store/selectors';
import { useCallback } from 'react';
@@ -9,12 +10,17 @@ import { useDispatch } from 'react-redux';
export const useCanvasUndoRedoHotkeys = () => {
useAssertSingleton('useCanvasUndoRedo');
const dispatch = useDispatch();
const isBusy = useCanvasIsBusy();
const mayUndo = useAppSelector(selectCanvasMayUndo);
const handleUndo = useCallback(() => {
dispatch(canvasUndo());
}, [dispatch]);
useHotkeys(['meta+z', 'ctrl+z'], handleUndo, { enabled: mayUndo, preventDefault: true }, [mayUndo, handleUndo]);
useHotkeys(['meta+z', 'ctrl+z'], handleUndo, { enabled: mayUndo && !isBusy, preventDefault: true }, [
mayUndo,
isBusy,
handleUndo,
]);
const mayRedo = useAppSelector(selectCanvasMayRedo);
const handleRedo = useCallback(() => {
@@ -23,7 +29,7 @@ export const useCanvasUndoRedoHotkeys = () => {
useHotkeys(
['meta+shift+z', 'ctrl+shift+z', 'meta+y', 'ctrl+y'],
handleRedo,
{ enabled: mayRedo, preventDefault: true },
[mayRedo, handleRedo]
{ enabled: mayRedo && !isBusy, preventDefault: true },
[mayRedo, handleRedo, isBusy]
);
};