mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-02-13 11:04:57 -05:00
feat(ui): viewer is a modal (wip)
This commit is contained in:
@@ -10,9 +10,11 @@ import type { PartialAppConfig } from 'app/types/invokeai';
|
||||
import { useFocusRegionWatcher } from 'common/hooks/focus';
|
||||
import { useGlobalHotkeys } from 'common/hooks/useGlobalHotkeys';
|
||||
import { useDynamicPromptsWatcher } from 'features/dynamicPrompts/hooks/useDynamicPromptsWatcher';
|
||||
import { toggleImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
|
||||
import { useStarterModelsToast } from 'features/modelManagerV2/hooks/useStarterModelsToast';
|
||||
import { useWorkflowBuilderWatcher } from 'features/nodes/components/sidePanel/workflow/IsolatedWorkflowBuilderWatcher';
|
||||
import { useReadinessWatcher } from 'features/queue/store/readiness';
|
||||
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
|
||||
import { configChanged } from 'features/system/store/configSlice';
|
||||
import { selectLanguage } from 'features/system/store/systemSelectors';
|
||||
import i18n from 'i18n';
|
||||
@@ -61,6 +63,12 @@ export const GlobalHookIsolator = memo(
|
||||
useWorkflowBuilderWatcher();
|
||||
useDynamicPromptsWatcher();
|
||||
|
||||
useRegisteredHotkeys({
|
||||
id: 'toggleViewer',
|
||||
category: 'viewer',
|
||||
callback: toggleImageViewer,
|
||||
});
|
||||
|
||||
return null;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -11,6 +11,7 @@ import { FullscreenDropzone } from 'features/dnd/FullscreenDropzone';
|
||||
import { DynamicPromptsModal } from 'features/dynamicPrompts/components/DynamicPromptsPreviewModal';
|
||||
import DeleteBoardModal from 'features/gallery/components/Boards/DeleteBoardModal';
|
||||
import { ImageContextMenu } from 'features/gallery/components/ImageContextMenu/ImageContextMenu';
|
||||
import { ImageViewerModal } from 'features/gallery/components/ImageViewer/ImageViewer';
|
||||
import { ShareWorkflowModal } from 'features/nodes/components/sidePanel/workflow/WorkflowLibrary/ShareWorkflowModal';
|
||||
import { WorkflowLibraryModal } from 'features/nodes/components/sidePanel/workflow/WorkflowLibrary/WorkflowLibraryModal';
|
||||
import { CancelAllExceptCurrentQueueItemConfirmationAlertDialog } from 'features/queue/components/CancelAllExceptCurrentQueueItemConfirmationAlertDialog';
|
||||
@@ -58,6 +59,7 @@ export const GlobalModalIsolator = memo(() => {
|
||||
<CanvasPasteModal />
|
||||
</CanvasManagerProviderGate>
|
||||
<LoadWorkflowFromGraphModal />
|
||||
<ImageViewerModal />
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -2,7 +2,6 @@ import { Grid, GridItem } from '@invoke-ai/ui-library';
|
||||
import { useCanvasIsBusy } from 'features/controlLayers/hooks/useCanvasIsBusy';
|
||||
import { newCanvasEntityFromImageDndTarget } from 'features/dnd/dnd';
|
||||
import { DndDropTarget } from 'features/dnd/DndDropTarget';
|
||||
import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
@@ -19,13 +18,8 @@ const addGlobalReferenceImageFromImageDndTargetData = newCanvasEntityFromImageDn
|
||||
|
||||
export const CanvasDropArea = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const imageViewer = useImageViewer();
|
||||
const isBusy = useCanvasIsBusy();
|
||||
|
||||
if (imageViewer.isOpen) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Grid
|
||||
|
||||
@@ -26,7 +26,6 @@ import { CanvasToolbar } from 'features/controlLayers/components/Toolbar/CanvasT
|
||||
import { Transform } from 'features/controlLayers/components/Transform/Transform';
|
||||
import { CanvasManagerProviderGate } from 'features/controlLayers/contexts/CanvasManagerProviderGate';
|
||||
import { selectDynamicGrid, selectShowHUD } from 'features/controlLayers/store/canvasSettingsSlice';
|
||||
import { GatedImageViewer } from 'features/gallery/components/ImageViewer/ImageViewer';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { PiDotsThreeOutlineVerticalFill } from 'react-icons/pi';
|
||||
|
||||
@@ -131,7 +130,6 @@ export const CanvasMainPanelContent = memo(() => {
|
||||
<CanvasManagerProviderGate>
|
||||
<CanvasDropArea />
|
||||
</CanvasManagerProviderGate>
|
||||
<GatedImageViewer />
|
||||
</Flex>
|
||||
</FocusRegionWrapper>
|
||||
);
|
||||
|
||||
@@ -11,7 +11,6 @@ import { DndDropOverlay } from 'features/dnd/DndDropOverlay';
|
||||
import type { DndTargetState } from 'features/dnd/types';
|
||||
import GalleryPanelContent from 'features/gallery/components/GalleryPanelContent';
|
||||
import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
|
||||
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
|
||||
import { selectActiveTabCanvasRightPanel } from 'features/ui/store/uiSelectors';
|
||||
import { activeTabCanvasRightPanelChanged } from 'features/ui/store/uiSlice';
|
||||
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
@@ -32,11 +31,8 @@ export const CanvasRightPanel = memo(() => {
|
||||
}, [activeTab]);
|
||||
|
||||
const onClickViewerToggleButton = useCallback(() => {
|
||||
if (activeTab !== 'gallery') {
|
||||
dispatch(activeTabCanvasRightPanelChanged('gallery'));
|
||||
}
|
||||
imageViewer.toggle();
|
||||
}, [imageViewer, activeTab, dispatch]);
|
||||
imageViewer.open();
|
||||
}, [imageViewer]);
|
||||
|
||||
const onChangeTab = useCallback(
|
||||
(index: number) => {
|
||||
@@ -49,20 +45,13 @@ export const CanvasRightPanel = memo(() => {
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
useRegisteredHotkeys({
|
||||
id: 'toggleViewer',
|
||||
category: 'viewer',
|
||||
callback: imageViewer.toggle,
|
||||
dependencies: [imageViewer],
|
||||
});
|
||||
|
||||
return (
|
||||
<Tabs index={tabIndex} onChange={onChangeTab} w="full" h="full" display="flex" flexDir="column">
|
||||
<TabList alignItems="center">
|
||||
<PanelTabs />
|
||||
<Spacer />
|
||||
<Button size="sm" variant="ghost" onClick={onClickViewerToggleButton}>
|
||||
{imageViewer.isOpen ? t('gallery.closeViewer') : t('gallery.openViewer')}
|
||||
{t('gallery.openViewer')}
|
||||
</Button>
|
||||
</TabList>
|
||||
<TabPanels w="full" h="full">
|
||||
|
||||
@@ -3,7 +3,6 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { useAssertSingleton } from 'common/hooks/useAssertSingleton';
|
||||
import { buildUseBoolean } from 'common/hooks/useBoolean';
|
||||
import { newCanvasSessionRequested, newGallerySessionRequested } from 'features/controlLayers/store/actions';
|
||||
import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
|
||||
import {
|
||||
selectSystemShouldConfirmOnNewSession,
|
||||
shouldConfirmOnNewSessionToggled,
|
||||
@@ -17,15 +16,13 @@ const [useNewCanvasSessionDialog] = buildUseBoolean(false);
|
||||
|
||||
export const useNewGallerySession = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const imageViewer = useImageViewer();
|
||||
const shouldConfirmOnNewSession = useAppSelector(selectSystemShouldConfirmOnNewSession);
|
||||
const newSessionDialog = useNewGallerySessionDialog();
|
||||
|
||||
const newGallerySessionImmediate = useCallback(() => {
|
||||
dispatch(newGallerySessionRequested());
|
||||
imageViewer.open();
|
||||
dispatch(activeTabCanvasRightPanelChanged('gallery'));
|
||||
}, [dispatch, imageViewer]);
|
||||
}, [dispatch]);
|
||||
|
||||
const newGallerySessionWithDialog = useCallback(() => {
|
||||
if (shouldConfirmOnNewSession) {
|
||||
@@ -40,15 +37,13 @@ export const useNewGallerySession = () => {
|
||||
|
||||
export const useNewCanvasSession = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const imageViewer = useImageViewer();
|
||||
const shouldConfirmOnNewSession = useAppSelector(selectSystemShouldConfirmOnNewSession);
|
||||
const newSessionDialog = useNewCanvasSessionDialog();
|
||||
|
||||
const newCanvasSessionImmediate = useCallback(() => {
|
||||
dispatch(newCanvasSessionRequested());
|
||||
imageViewer.close();
|
||||
dispatch(activeTabCanvasRightPanelChanged('layers'));
|
||||
}, [dispatch, imageViewer]);
|
||||
}, [dispatch]);
|
||||
|
||||
const newCanvasSessionWithDialog = useCallback(() => {
|
||||
if (shouldConfirmOnNewSession) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { IconButton, Tooltip } from '@invoke-ai/ui-library';
|
||||
import { useSelectTool, useToolIsSelected } from 'features/controlLayers/components/Tool/hooks';
|
||||
import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
|
||||
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -10,14 +9,13 @@ export const ToolBboxButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const selectBbox = useSelectTool('bbox');
|
||||
const isSelected = useToolIsSelected('bbox');
|
||||
const imageViewer = useImageViewer();
|
||||
|
||||
useRegisteredHotkeys({
|
||||
id: 'selectBboxTool',
|
||||
category: 'canvas',
|
||||
callback: selectBbox,
|
||||
options: { enabled: !isSelected && !imageViewer.isOpen },
|
||||
dependencies: [selectBbox, isSelected, imageViewer.isOpen],
|
||||
options: { enabled: !isSelected },
|
||||
dependencies: [selectBbox, isSelected],
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { IconButton, Tooltip } from '@invoke-ai/ui-library';
|
||||
import { useSelectTool, useToolIsSelected } from 'features/controlLayers/components/Tool/hooks';
|
||||
import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
|
||||
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -10,14 +9,13 @@ export const ToolBrushButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const isSelected = useToolIsSelected('brush');
|
||||
const selectBrush = useSelectTool('brush');
|
||||
const imageViewer = useImageViewer();
|
||||
|
||||
useRegisteredHotkeys({
|
||||
id: 'selectBrushTool',
|
||||
category: 'canvas',
|
||||
callback: selectBrush,
|
||||
options: { enabled: !isSelected && !imageViewer.isOpen },
|
||||
dependencies: [isSelected, selectBrush, imageViewer.isOpen],
|
||||
options: { enabled: !isSelected },
|
||||
dependencies: [isSelected, selectBrush],
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
@@ -16,7 +16,6 @@ import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { useToolIsSelected } from 'features/controlLayers/components/Tool/hooks';
|
||||
import { selectCanvasSettingsSlice, settingsBrushWidthChanged } from 'features/controlLayers/store/canvasSettingsSlice';
|
||||
import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
|
||||
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
|
||||
import { clamp } from 'lodash-es';
|
||||
import type { KeyboardEvent } from 'react';
|
||||
@@ -69,7 +68,6 @@ const sliderDefaultValue = mapRawValueToSliderValue(50);
|
||||
export const ToolBrushWidth = memo(() => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
const imageViewer = useImageViewer();
|
||||
const isSelected = useToolIsSelected('brush');
|
||||
const width = useAppSelector(selectBrushWidth);
|
||||
const [localValue, setLocalValue] = useState(width);
|
||||
@@ -133,15 +131,15 @@ export const ToolBrushWidth = memo(() => {
|
||||
id: 'decrementToolWidth',
|
||||
category: 'canvas',
|
||||
callback: decrement,
|
||||
options: { enabled: isSelected && !imageViewer.isOpen },
|
||||
dependencies: [decrement, isSelected, imageViewer.isOpen],
|
||||
options: { enabled: isSelected },
|
||||
dependencies: [decrement, isSelected],
|
||||
});
|
||||
useRegisteredHotkeys({
|
||||
id: 'incrementToolWidth',
|
||||
category: 'canvas',
|
||||
callback: increment,
|
||||
options: { enabled: isSelected && !imageViewer.isOpen },
|
||||
dependencies: [increment, isSelected, imageViewer.isOpen],
|
||||
options: { enabled: isSelected },
|
||||
dependencies: [increment, isSelected],
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { IconButton, Tooltip } from '@invoke-ai/ui-library';
|
||||
import { useSelectTool, useToolIsSelected } from 'features/controlLayers/components/Tool/hooks';
|
||||
import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
|
||||
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -10,14 +9,13 @@ export const ToolColorPickerButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const isSelected = useToolIsSelected('colorPicker');
|
||||
const selectColorPicker = useSelectTool('colorPicker');
|
||||
const imageViewer = useImageViewer();
|
||||
|
||||
useRegisteredHotkeys({
|
||||
id: 'selectColorPickerTool',
|
||||
category: 'canvas',
|
||||
callback: selectColorPicker,
|
||||
options: { enabled: !isSelected && !imageViewer.isOpen },
|
||||
dependencies: [selectColorPicker, isSelected, imageViewer.isOpen],
|
||||
options: { enabled: !isSelected },
|
||||
dependencies: [selectColorPicker, isSelected],
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { IconButton, Tooltip } from '@invoke-ai/ui-library';
|
||||
import { useSelectTool, useToolIsSelected } from 'features/controlLayers/components/Tool/hooks';
|
||||
import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
|
||||
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -10,14 +9,13 @@ export const ToolEraserButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const isSelected = useToolIsSelected('eraser');
|
||||
const selectEraser = useSelectTool('eraser');
|
||||
const imageViewer = useImageViewer();
|
||||
|
||||
useRegisteredHotkeys({
|
||||
id: 'selectEraserTool',
|
||||
category: 'canvas',
|
||||
callback: selectEraser,
|
||||
options: { enabled: !isSelected && !imageViewer.isOpen },
|
||||
dependencies: [isSelected, selectEraser, imageViewer.isOpen],
|
||||
options: { enabled: !isSelected },
|
||||
dependencies: [isSelected, selectEraser],
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
@@ -19,7 +19,6 @@ import {
|
||||
selectCanvasSettingsSlice,
|
||||
settingsEraserWidthChanged,
|
||||
} from 'features/controlLayers/store/canvasSettingsSlice';
|
||||
import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
|
||||
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
|
||||
import { clamp } from 'lodash-es';
|
||||
import type { KeyboardEvent } from 'react';
|
||||
@@ -72,7 +71,6 @@ const sliderDefaultValue = mapRawValueToSliderValue(50);
|
||||
export const ToolEraserWidth = memo(() => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
const imageViewer = useImageViewer();
|
||||
const isSelected = useToolIsSelected('eraser');
|
||||
const width = useAppSelector(selectEraserWidth);
|
||||
const [localValue, setLocalValue] = useState(width);
|
||||
@@ -136,15 +134,15 @@ export const ToolEraserWidth = memo(() => {
|
||||
id: 'decrementToolWidth',
|
||||
category: 'canvas',
|
||||
callback: decrement,
|
||||
options: { enabled: isSelected && !imageViewer.isOpen },
|
||||
dependencies: [decrement, isSelected, imageViewer.isOpen],
|
||||
options: { enabled: isSelected },
|
||||
dependencies: [decrement, isSelected],
|
||||
});
|
||||
useRegisteredHotkeys({
|
||||
id: 'incrementToolWidth',
|
||||
category: 'canvas',
|
||||
callback: increment,
|
||||
options: { enabled: isSelected && !imageViewer.isOpen },
|
||||
dependencies: [increment, isSelected, imageViewer.isOpen],
|
||||
options: { enabled: isSelected },
|
||||
dependencies: [increment, isSelected],
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
@@ -14,7 +14,6 @@ import RgbaColorPicker from 'common/components/ColorPicker/RgbaColorPicker';
|
||||
import { rgbaColorToString } from 'common/util/colorCodeTransformers';
|
||||
import { selectCanvasSettingsSlice, settingsColorChanged } from 'features/controlLayers/store/canvasSettingsSlice';
|
||||
import type { RgbaColor } from 'features/controlLayers/store/types';
|
||||
import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
|
||||
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -31,14 +30,13 @@ export const ToolColorPicker = memo(() => {
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
const imageViewer = useImageViewer();
|
||||
|
||||
useRegisteredHotkeys({
|
||||
id: 'setFillToWhite',
|
||||
category: 'canvas',
|
||||
callback: () => dispatch(settingsColorChanged({ r: 255, g: 255, b: 255, a: 1 })),
|
||||
options: { preventDefault: true, enabled: !imageViewer.isOpen },
|
||||
dependencies: [dispatch, imageViewer.isOpen],
|
||||
options: { preventDefault: true },
|
||||
dependencies: [dispatch],
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { IconButton, Tooltip } from '@invoke-ai/ui-library';
|
||||
import { useSelectTool, useToolIsSelected } from 'features/controlLayers/components/Tool/hooks';
|
||||
import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
|
||||
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -10,14 +9,13 @@ export const ToolMoveButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const isSelected = useToolIsSelected('move');
|
||||
const selectMove = useSelectTool('move');
|
||||
const imageViewer = useImageViewer();
|
||||
|
||||
useRegisteredHotkeys({
|
||||
id: 'selectMoveTool',
|
||||
category: 'canvas',
|
||||
callback: selectMove,
|
||||
options: { enabled: !isSelected && !imageViewer.isOpen },
|
||||
dependencies: [isSelected, selectMove, imageViewer.isOpen],
|
||||
options: { enabled: !isSelected },
|
||||
dependencies: [isSelected, selectMove],
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { IconButton, Tooltip } from '@invoke-ai/ui-library';
|
||||
import { useSelectTool, useToolIsSelected } from 'features/controlLayers/components/Tool/hooks';
|
||||
import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
|
||||
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -10,14 +9,13 @@ export const ToolRectButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const isSelected = useToolIsSelected('rect');
|
||||
const selectRect = useSelectTool('rect');
|
||||
const imageViewer = useImageViewer();
|
||||
|
||||
useRegisteredHotkeys({
|
||||
id: 'selectRectTool',
|
||||
category: 'canvas',
|
||||
callback: selectRect,
|
||||
options: { enabled: !isSelected && !imageViewer.isOpen },
|
||||
dependencies: [isSelected, selectRect, imageViewer.isOpen],
|
||||
options: { enabled: !isSelected },
|
||||
dependencies: [isSelected, selectRect],
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { IconButton, Tooltip } from '@invoke-ai/ui-library';
|
||||
import { useSelectTool, useToolIsSelected } from 'features/controlLayers/components/Tool/hooks';
|
||||
import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
|
||||
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -10,14 +9,13 @@ export const ToolViewButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const isSelected = useToolIsSelected('view');
|
||||
const selectView = useSelectTool('view');
|
||||
const imageViewer = useImageViewer();
|
||||
|
||||
useRegisteredHotkeys({
|
||||
id: 'selectViewTool',
|
||||
category: 'canvas',
|
||||
callback: selectView,
|
||||
options: { enabled: !isSelected && !imageViewer.isOpen },
|
||||
dependencies: [selectView, isSelected, imageViewer.isOpen],
|
||||
options: { enabled: !isSelected },
|
||||
dependencies: [selectView, isSelected],
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { IconButton } from '@invoke-ai/ui-library';
|
||||
import { useIsRegionFocused } from 'common/hooks/focus';
|
||||
import { useCanvasManager } from 'features/controlLayers/contexts/CanvasManagerProviderGate';
|
||||
import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
|
||||
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -11,49 +10,48 @@ export const CanvasToolbarResetViewButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const canvasManager = useCanvasManager();
|
||||
const isCanvasFocused = useIsRegionFocused('canvas');
|
||||
const imageViewer = useImageViewer();
|
||||
|
||||
useRegisteredHotkeys({
|
||||
id: 'fitLayersToCanvas',
|
||||
category: 'canvas',
|
||||
callback: canvasManager.stage.fitLayersToStage,
|
||||
options: { enabled: isCanvasFocused && !imageViewer.isOpen, preventDefault: true },
|
||||
dependencies: [isCanvasFocused, imageViewer.isOpen],
|
||||
options: { enabled: isCanvasFocused, preventDefault: true },
|
||||
dependencies: [isCanvasFocused],
|
||||
});
|
||||
useRegisteredHotkeys({
|
||||
id: 'fitBboxToCanvas',
|
||||
category: 'canvas',
|
||||
callback: canvasManager.stage.fitBboxToStage,
|
||||
options: { enabled: isCanvasFocused && !imageViewer.isOpen, preventDefault: true },
|
||||
dependencies: [isCanvasFocused, imageViewer.isOpen],
|
||||
options: { enabled: isCanvasFocused, preventDefault: true },
|
||||
dependencies: [isCanvasFocused],
|
||||
});
|
||||
useRegisteredHotkeys({
|
||||
id: 'setZoomTo100Percent',
|
||||
category: 'canvas',
|
||||
callback: () => canvasManager.stage.setScale(1),
|
||||
options: { enabled: isCanvasFocused && !imageViewer.isOpen, preventDefault: true },
|
||||
dependencies: [isCanvasFocused, imageViewer.isOpen],
|
||||
options: { enabled: isCanvasFocused, preventDefault: true },
|
||||
dependencies: [isCanvasFocused],
|
||||
});
|
||||
useRegisteredHotkeys({
|
||||
id: 'setZoomTo200Percent',
|
||||
category: 'canvas',
|
||||
callback: () => canvasManager.stage.setScale(2),
|
||||
options: { enabled: isCanvasFocused && !imageViewer.isOpen, preventDefault: true },
|
||||
dependencies: [isCanvasFocused, imageViewer.isOpen],
|
||||
options: { enabled: isCanvasFocused, preventDefault: true },
|
||||
dependencies: [isCanvasFocused],
|
||||
});
|
||||
useRegisteredHotkeys({
|
||||
id: 'setZoomTo400Percent',
|
||||
category: 'canvas',
|
||||
callback: () => canvasManager.stage.setScale(4),
|
||||
options: { enabled: isCanvasFocused && !imageViewer.isOpen, preventDefault: true },
|
||||
dependencies: [isCanvasFocused, imageViewer.isOpen],
|
||||
options: { enabled: isCanvasFocused, preventDefault: true },
|
||||
dependencies: [isCanvasFocused],
|
||||
});
|
||||
useRegisteredHotkeys({
|
||||
id: 'setZoomTo800Percent',
|
||||
category: 'canvas',
|
||||
callback: () => canvasManager.stage.setScale(8),
|
||||
options: { enabled: isCanvasFocused && !imageViewer.isOpen, preventDefault: true },
|
||||
dependencies: [isCanvasFocused, imageViewer.isOpen],
|
||||
options: { enabled: isCanvasFocused, preventDefault: true },
|
||||
dependencies: [isCanvasFocused],
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
@@ -3,7 +3,6 @@ import { useAssertSingleton } from 'common/hooks/useAssertSingleton';
|
||||
import { useCanvasIsBusy } from 'features/controlLayers/hooks/useCanvasIsBusy';
|
||||
import { entityDeleted } from 'features/controlLayers/store/canvasSlice';
|
||||
import { selectSelectedEntityIdentifier } from 'features/controlLayers/store/selectors';
|
||||
import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
|
||||
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
|
||||
import { selectActiveTab, selectActiveTabCanvasRightPanel } from 'features/ui/store/uiSelectors';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
@@ -16,8 +15,6 @@ export function useCanvasDeleteLayerHotkey() {
|
||||
const canvasRightPanelTab = useAppSelector(selectActiveTabCanvasRightPanel);
|
||||
const appTab = useAppSelector(selectActiveTab);
|
||||
|
||||
const imageViewer = useImageViewer();
|
||||
|
||||
const deleteSelectedLayer = useCallback(() => {
|
||||
if (selectedEntityIdentifier === null) {
|
||||
return;
|
||||
@@ -34,7 +31,7 @@ export function useCanvasDeleteLayerHotkey() {
|
||||
id: 'deleteSelected',
|
||||
category: 'canvas',
|
||||
callback: deleteSelectedLayer,
|
||||
options: { enabled: isDeleteEnabled && !imageViewer.isOpen },
|
||||
dependencies: [isDeleteEnabled, deleteSelectedLayer, imageViewer.isOpen],
|
||||
options: { enabled: isDeleteEnabled },
|
||||
dependencies: [isDeleteEnabled, deleteSelectedLayer],
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
selectSelectedEntityIdentifier,
|
||||
} from 'features/controlLayers/store/selectors';
|
||||
import type { CanvasEntityIdentifier } from 'features/controlLayers/store/types';
|
||||
import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
|
||||
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
@@ -15,7 +14,6 @@ export const useCanvasEntityQuickSwitchHotkey = () => {
|
||||
const [current, setCurrent] = useState<CanvasEntityIdentifier | null>(null);
|
||||
const selected = useAppSelector(selectSelectedEntityIdentifier);
|
||||
const bookmarked = useAppSelector(selectBookmarkedEntityIdentifier);
|
||||
const imageViewer = useImageViewer();
|
||||
|
||||
// Update prev and current when selected entity changes
|
||||
useEffect(() => {
|
||||
@@ -49,7 +47,6 @@ export const useCanvasEntityQuickSwitchHotkey = () => {
|
||||
id: 'quickSwitch',
|
||||
category: 'canvas',
|
||||
callback: onQuickSwitch,
|
||||
options: { enabled: !imageViewer.isOpen },
|
||||
dependencies: [onQuickSwitch, imageViewer.isOpen],
|
||||
dependencies: [onQuickSwitch],
|
||||
});
|
||||
};
|
||||
|
||||
@@ -6,7 +6,6 @@ import { useEntityIsLocked } from 'features/controlLayers/hooks/useEntityIsLocke
|
||||
import { entityReset } from 'features/controlLayers/store/canvasSlice';
|
||||
import { selectSelectedEntityIdentifier } from 'features/controlLayers/store/selectors';
|
||||
import { isMaskEntityIdentifier } from 'features/controlLayers/store/types';
|
||||
import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
|
||||
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
|
||||
@@ -17,7 +16,6 @@ export function useCanvasResetLayerHotkey() {
|
||||
const isBusy = useCanvasIsBusy();
|
||||
const adapter = useEntityAdapterSafe(entityIdentifier);
|
||||
const isLocked = useEntityIsLocked(entityIdentifier);
|
||||
const imageViewer = useImageViewer();
|
||||
|
||||
const resetSelectedLayer = useCallback(() => {
|
||||
if (entityIdentifier === null || adapter === null) {
|
||||
@@ -36,7 +34,7 @@ export function useCanvasResetLayerHotkey() {
|
||||
id: 'resetSelected',
|
||||
category: 'canvas',
|
||||
callback: resetSelectedLayer,
|
||||
options: { enabled: isResetAllowed && !isBusy && !isLocked && !imageViewer.isOpen },
|
||||
dependencies: [isResetAllowed, isBusy, isLocked, resetSelectedLayer, imageViewer.isOpen],
|
||||
options: { enabled: isResetAllowed && !isBusy && !isLocked },
|
||||
dependencies: [isResetAllowed, isBusy, isLocked, resetSelectedLayer],
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ 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 { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
|
||||
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
|
||||
import { useCallback } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
@@ -12,7 +11,6 @@ export const useCanvasUndoRedoHotkeys = () => {
|
||||
useAssertSingleton('useCanvasUndoRedo');
|
||||
const dispatch = useDispatch();
|
||||
const isBusy = useCanvasIsBusy();
|
||||
const imageViewer = useImageViewer();
|
||||
|
||||
const mayUndo = useAppSelector(selectCanvasMayUndo);
|
||||
const handleUndo = useCallback(() => {
|
||||
@@ -22,8 +20,8 @@ export const useCanvasUndoRedoHotkeys = () => {
|
||||
id: 'undo',
|
||||
category: 'canvas',
|
||||
callback: handleUndo,
|
||||
options: { enabled: mayUndo && !isBusy && !imageViewer.isOpen, preventDefault: true },
|
||||
dependencies: [mayUndo, isBusy, handleUndo, imageViewer.isOpen],
|
||||
options: { enabled: mayUndo && !isBusy, preventDefault: true },
|
||||
dependencies: [mayUndo, isBusy, handleUndo],
|
||||
});
|
||||
|
||||
const mayRedo = useAppSelector(selectCanvasMayRedo);
|
||||
@@ -34,7 +32,7 @@ export const useCanvasUndoRedoHotkeys = () => {
|
||||
id: 'redo',
|
||||
category: 'canvas',
|
||||
callback: handleRedo,
|
||||
options: { enabled: mayRedo && !isBusy && !imageViewer.isOpen, preventDefault: true },
|
||||
dependencies: [mayRedo, handleRedo, isBusy, imageViewer.isOpen],
|
||||
options: { enabled: mayRedo && !isBusy, preventDefault: true },
|
||||
dependencies: [mayRedo, handleRedo, isBusy],
|
||||
});
|
||||
};
|
||||
|
||||
@@ -5,13 +5,11 @@ import { useEntityIsEmpty } from 'features/controlLayers/hooks/useEntityIsEmpty'
|
||||
import { useEntityIsLocked } from 'features/controlLayers/hooks/useEntityIsLocked';
|
||||
import type { CanvasEntityIdentifier } from 'features/controlLayers/store/types';
|
||||
import { isFilterableEntityIdentifier } from 'features/controlLayers/store/types';
|
||||
import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
|
||||
export const useEntityFilter = (entityIdentifier: CanvasEntityIdentifier | null) => {
|
||||
const canvasManager = useCanvasManager();
|
||||
const adapter = useEntityAdapterSafe(entityIdentifier);
|
||||
const imageViewer = useImageViewer();
|
||||
const isBusy = useCanvasIsBusy();
|
||||
const isLocked = useEntityIsLocked(entityIdentifier);
|
||||
const isEmpty = useEntityIsEmpty(entityIdentifier);
|
||||
@@ -52,9 +50,8 @@ export const useEntityFilter = (entityIdentifier: CanvasEntityIdentifier | null)
|
||||
if (!adapter) {
|
||||
return;
|
||||
}
|
||||
imageViewer.close();
|
||||
adapter.filterer.start();
|
||||
}, [isDisabled, entityIdentifier, canvasManager, imageViewer]);
|
||||
}, [isDisabled, entityIdentifier, canvasManager]);
|
||||
|
||||
return { isDisabled, start } as const;
|
||||
};
|
||||
|
||||
@@ -5,13 +5,11 @@ import { useEntityIsEmpty } from 'features/controlLayers/hooks/useEntityIsEmpty'
|
||||
import { useEntityIsLocked } from 'features/controlLayers/hooks/useEntityIsLocked';
|
||||
import type { CanvasEntityIdentifier } from 'features/controlLayers/store/types';
|
||||
import { isSegmentableEntityIdentifier } from 'features/controlLayers/store/types';
|
||||
import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
|
||||
export const useEntitySegmentAnything = (entityIdentifier: CanvasEntityIdentifier | null) => {
|
||||
const canvasManager = useCanvasManager();
|
||||
const adapter = useEntityAdapterSafe(entityIdentifier);
|
||||
const imageViewer = useImageViewer();
|
||||
const isBusy = useCanvasIsBusy();
|
||||
const isLocked = useEntityIsLocked(entityIdentifier);
|
||||
const isEmpty = useEntityIsEmpty(entityIdentifier);
|
||||
@@ -52,9 +50,8 @@ export const useEntitySegmentAnything = (entityIdentifier: CanvasEntityIdentifie
|
||||
if (!adapter) {
|
||||
return;
|
||||
}
|
||||
imageViewer.close();
|
||||
adapter.segmentAnything.start();
|
||||
}, [isDisabled, entityIdentifier, canvasManager, imageViewer]);
|
||||
}, [isDisabled, entityIdentifier, canvasManager]);
|
||||
|
||||
return { isDisabled, start } as const;
|
||||
};
|
||||
|
||||
@@ -5,13 +5,11 @@ import { useEntityIsEmpty } from 'features/controlLayers/hooks/useEntityIsEmpty'
|
||||
import { useEntityIsLocked } from 'features/controlLayers/hooks/useEntityIsLocked';
|
||||
import type { CanvasEntityIdentifier } from 'features/controlLayers/store/types';
|
||||
import { isTransformableEntityIdentifier } from 'features/controlLayers/store/types';
|
||||
import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
|
||||
export const useEntityTransform = (entityIdentifier: CanvasEntityIdentifier | null) => {
|
||||
const canvasManager = useCanvasManager();
|
||||
const adapter = useEntityAdapterSafe(entityIdentifier);
|
||||
const imageViewer = useImageViewer();
|
||||
const isBusy = useCanvasIsBusy();
|
||||
const isLocked = useEntityIsLocked(entityIdentifier);
|
||||
const isEmpty = useEntityIsEmpty(entityIdentifier);
|
||||
@@ -52,9 +50,8 @@ export const useEntityTransform = (entityIdentifier: CanvasEntityIdentifier | nu
|
||||
if (!adapter) {
|
||||
return;
|
||||
}
|
||||
imageViewer.close();
|
||||
await adapter.transformer.startTransform();
|
||||
}, [isDisabled, entityIdentifier, canvasManager, imageViewer]);
|
||||
}, [isDisabled, entityIdentifier, canvasManager]);
|
||||
|
||||
const fitToBbox = useCallback(async () => {
|
||||
if (isDisabled) {
|
||||
@@ -70,11 +67,10 @@ export const useEntityTransform = (entityIdentifier: CanvasEntityIdentifier | nu
|
||||
if (!adapter) {
|
||||
return;
|
||||
}
|
||||
imageViewer.close();
|
||||
await adapter.transformer.startTransform({ silent: true });
|
||||
adapter.transformer.fitToBboxContain();
|
||||
await adapter.transformer.applyTransform();
|
||||
}, [canvasManager, entityIdentifier, imageViewer, isDisabled]);
|
||||
}, [canvasManager, entityIdentifier, isDisabled]);
|
||||
|
||||
return { isDisabled, start, fitToBbox } as const;
|
||||
};
|
||||
|
||||
@@ -8,6 +8,7 @@ import type { DndDragPreviewSingleImageState } from 'features/dnd/DndDragPreview
|
||||
import { createSingleImageDragPreview, setSingleImageDragPreview } from 'features/dnd/DndDragPreviewSingleImage';
|
||||
import { firefoxDndFix } from 'features/dnd/util';
|
||||
import { useImageContextMenu } from 'features/gallery/components/ImageContextMenu/ImageContextMenu';
|
||||
import { $imageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
|
||||
import { memo, useEffect, useState } from 'react';
|
||||
import type { ImageDTO } from 'services/api/types';
|
||||
|
||||
@@ -47,6 +48,9 @@ export const DndImage = memo(({ imageDTO, asThumbnail, ...rest }: DndImage.Props
|
||||
getInitialData: () => singleImageDndSource.getData({ imageDTO }, imageDTO.image_name),
|
||||
onDragStart: () => {
|
||||
setIsDragging(true);
|
||||
if ($imageViewer.get()) {
|
||||
$imageViewer.set(false);
|
||||
}
|
||||
},
|
||||
onDrop: () => {
|
||||
setIsDragging(false);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Box, IconButton, type SystemStyleObject } from '@invoke-ai/ui-library';
|
||||
import { Box, IconButton, type SystemStyleObject, useOutsideClick } from '@invoke-ai/ui-library';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { FocusRegionWrapper } from 'common/components/FocusRegionWrapper';
|
||||
import { useAssertSingleton } from 'common/hooks/useAssertSingleton';
|
||||
@@ -9,7 +9,7 @@ import { ImageComparisonDroppable } from 'features/gallery/components/ImageViewe
|
||||
import { ViewerToolbar } from 'features/gallery/components/ImageViewer/ViewerToolbar';
|
||||
import { selectHasImageToCompare } from 'features/gallery/store/gallerySelectors';
|
||||
import type { ReactNode } from 'react';
|
||||
import { memo } from 'react';
|
||||
import { memo, useRef } from 'react';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiXBold } from 'react-icons/pi';
|
||||
@@ -43,7 +43,7 @@ export const ImageViewer = memo(({ closeButton }: Props) => {
|
||||
const [containerRef, containerDims] = useMeasure<HTMLDivElement>();
|
||||
|
||||
return (
|
||||
<FocusRegionWrapper region="viewer" sx={FOCUS_REGION_STYLES} layerStyle="first" {...useFocusRegionOptions}>
|
||||
<FocusRegionWrapper region="viewer" sx={FOCUS_REGION_STYLES} {...useFocusRegionOptions}>
|
||||
{hasImageToCompare && <CompareToolbar />}
|
||||
{!hasImageToCompare && <ViewerToolbar closeButton={closeButton} />}
|
||||
<Box ref={containerRef} w="full" h="full" p={2} overflow="hidden">
|
||||
@@ -57,17 +57,50 @@ export const ImageViewer = memo(({ closeButton }: Props) => {
|
||||
|
||||
ImageViewer.displayName = 'ImageViewer';
|
||||
|
||||
export const GatedImageViewer = memo(() => {
|
||||
const imageViewerContainerSx: SystemStyleObject = {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
transition: 'opacity 0.15s ease',
|
||||
opacity: 1,
|
||||
pointerEvents: 'auto',
|
||||
'&[data-hidden="true"]': {
|
||||
opacity: 0,
|
||||
pointerEvents: 'none',
|
||||
},
|
||||
backdropFilter: 'blur(10px) brightness(70%)',
|
||||
};
|
||||
|
||||
const imageViewerModalSx: SystemStyleObject = {
|
||||
position: 'absolute',
|
||||
bg: 'base.800',
|
||||
borderRadius: 'base',
|
||||
top: 16,
|
||||
right: 16,
|
||||
bottom: 16,
|
||||
left: 16,
|
||||
};
|
||||
|
||||
export const ImageViewerModal = memo(() => {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const imageViewer = useImageViewer();
|
||||
useOutsideClick({
|
||||
ref,
|
||||
handler: imageViewer.close,
|
||||
});
|
||||
|
||||
if (!imageViewer.isOpen) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <ImageViewer closeButton={<ImageViewerCloseButton />} />;
|
||||
return (
|
||||
<Box sx={imageViewerContainerSx} data-hidden={!imageViewer.isOpen}>
|
||||
<Box ref={ref} sx={imageViewerModalSx}>
|
||||
<ImageViewer closeButton={<ImageViewerCloseButton />} />
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
});
|
||||
|
||||
GatedImageViewer.displayName = 'GatedImageViewer';
|
||||
ImageViewerModal.displayName = 'GatedImageViewer';
|
||||
|
||||
const ImageViewerCloseButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
@@ -87,15 +120,3 @@ const ImageViewerCloseButton = memo(() => {
|
||||
});
|
||||
|
||||
ImageViewerCloseButton.displayName = 'ImageViewerCloseButton';
|
||||
|
||||
const GatedImageViewerCloseButton = memo(() => {
|
||||
const imageViewer = useImageViewer();
|
||||
|
||||
if (!imageViewer.isOpen) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <ImageViewerCloseButton />;
|
||||
});
|
||||
|
||||
GatedImageViewerCloseButton.displayName = 'GatedImageViewerCloseButton';
|
||||
|
||||
@@ -27,9 +27,10 @@ import type { ImageDTO } from 'services/api/types';
|
||||
* TODO(psyche): Figure out a better way to do handle this...
|
||||
*/
|
||||
let didCloseImageViewer = false;
|
||||
const api = buildUseBoolean(true);
|
||||
const api = buildUseBoolean(false);
|
||||
const useImageViewerState = api[0];
|
||||
export const $imageViewer = api[1];
|
||||
export const toggleImageViewer = () => $imageViewer.set(!$imageViewer.get());
|
||||
|
||||
export const useImageViewer = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
@@ -2,7 +2,6 @@ import { ButtonGroup, Flex, Icon, IconButton, spinAnimation, Tooltip, useShiftMo
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { ToolChooser } from 'features/controlLayers/components/Tool/ToolChooser';
|
||||
import { CanvasManagerProviderGate } from 'features/controlLayers/contexts/CanvasManagerProviderGate';
|
||||
import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
|
||||
import { useCancelAllExceptCurrentQueueItemDialog } from 'features/queue/components/CancelAllExceptCurrentQueueItemConfirmationAlertDialog';
|
||||
import { useClearQueueDialog } from 'features/queue/components/ClearQueueConfirmationAlertDialog';
|
||||
import { InvokeButtonTooltip } from 'features/queue/components/InvokeButtonTooltip/InvokeButtonTooltip';
|
||||
@@ -30,12 +29,11 @@ type Props = {
|
||||
const FloatingSidePanelButtons = ({ togglePanel }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const tab = useAppSelector(selectActiveTab);
|
||||
const imageViewer = useImageViewer();
|
||||
const isCancelAndClearAllEnabled = useFeatureStatus('cancelAndClearAll');
|
||||
|
||||
return (
|
||||
<Flex pos="absolute" transform="translate(0, -50%)" top="50%" insetInlineStart={2} direction="column" gap={2}>
|
||||
{tab === 'canvas' && !imageViewer.isOpen && (
|
||||
{tab === 'canvas' && (
|
||||
<CanvasManagerProviderGate>
|
||||
<ToolChooser />
|
||||
</CanvasManagerProviderGate>
|
||||
|
||||
Reference in New Issue
Block a user