mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-02-17 05:21:19 -05:00
locate in gallery image context menu
This commit is contained in:
committed by
psychedelicious
parent
9c1eb263a8
commit
19cd6eed08
@@ -38,6 +38,7 @@
|
||||
"deletedImagesCannotBeRestored": "Deleted images cannot be restored.",
|
||||
"hideBoards": "Hide Boards",
|
||||
"loading": "Loading...",
|
||||
"locateInGalery": "Locate in Gallery",
|
||||
"menuItemAutoAdd": "Auto-add to this Board",
|
||||
"move": "Move",
|
||||
"movingImagesToBoard_one": "Moving {{count}} image to board:",
|
||||
|
||||
@@ -7,13 +7,7 @@ import { useGallerySearchTerm } from 'features/gallery/components/ImageGrid/useG
|
||||
import { selectSelectedBoardId } from 'features/gallery/store/gallerySelectors';
|
||||
import { galleryViewChanged, selectGallerySlice } from 'features/gallery/store/gallerySlice';
|
||||
import { useAutoLayoutContext } from 'features/ui/layouts/auto-layout-context';
|
||||
import {
|
||||
GALLERY_PANEL_DEFAULT_HEIGHT_PX,
|
||||
GALLERY_PANEL_ID,
|
||||
GALLERY_PANEL_MIN_EXPANDED_HEIGHT_PX,
|
||||
GALLERY_PANEL_MIN_HEIGHT_PX,
|
||||
} from 'features/ui/layouts/shared';
|
||||
import { useCollapsibleGridviewPanel } from 'features/ui/layouts/use-collapsible-gridview-panel';
|
||||
import { useGalleryPanel } from 'features/ui/layouts/use-gallery-panel';
|
||||
import type { CSSProperties } from 'react';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -34,16 +28,8 @@ export const GalleryPanel = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const { tab } = useAutoLayoutContext();
|
||||
const collapsibleApi = useCollapsibleGridviewPanel(
|
||||
tab,
|
||||
GALLERY_PANEL_ID,
|
||||
'vertical',
|
||||
GALLERY_PANEL_DEFAULT_HEIGHT_PX,
|
||||
GALLERY_PANEL_MIN_HEIGHT_PX,
|
||||
GALLERY_PANEL_MIN_EXPANDED_HEIGHT_PX
|
||||
);
|
||||
const isCollapsed = useStore(collapsibleApi.$isCollapsed);
|
||||
|
||||
const galleryPanel = useGalleryPanel(tab);
|
||||
const isCollapsed = useStore(galleryPanel.$isCollapsed);
|
||||
const galleryView = useAppSelector(selectGalleryView);
|
||||
const initialSearchTerm = useAppSelector(selectSearchTerm);
|
||||
const searchDisclosure = useDisclosure(!!initialSearchTerm);
|
||||
@@ -58,11 +44,11 @@ export const GalleryPanel = memo(() => {
|
||||
|
||||
const handleClickSearch = useCallback(() => {
|
||||
onResetSearchTerm();
|
||||
if (!searchDisclosure.isOpen && collapsibleApi.$isCollapsed.get()) {
|
||||
collapsibleApi.expand();
|
||||
if (!searchDisclosure.isOpen && galleryPanel.$isCollapsed.get()) {
|
||||
galleryPanel.expand();
|
||||
}
|
||||
searchDisclosure.toggle();
|
||||
}, [collapsibleApi, onResetSearchTerm, searchDisclosure]);
|
||||
}, [galleryPanel, onResetSearchTerm, searchDisclosure]);
|
||||
|
||||
const selectedBoardId = useAppSelector(selectSelectedBoardId);
|
||||
const boardName = useBoardName(selectedBoardId);
|
||||
@@ -73,7 +59,7 @@ export const GalleryPanel = memo(() => {
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={collapsibleApi.toggle}
|
||||
onClick={galleryPanel.toggle}
|
||||
leftIcon={isCollapsed ? <PiCaretDownBold /> : <PiCaretUpBold />}
|
||||
noOfLines={1}
|
||||
>
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import { MenuItem } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { useImageDTOContext } from 'features/gallery/contexts/ImageDTOContext';
|
||||
import { boardIdSelected } from 'features/gallery/store/gallerySlice';
|
||||
import { navigationApi } from 'features/ui/layouts/navigation-api';
|
||||
import { useGalleryPanel } from 'features/ui/layouts/use-gallery-panel';
|
||||
import { selectActiveTab } from 'features/ui/store/uiSelectors';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiCrosshair } from 'react-icons/pi';
|
||||
|
||||
export const ImageMenuItemLocateInGalery = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const imageDTO = useImageDTOContext();
|
||||
const activeTab = useAppSelector(selectActiveTab);
|
||||
const galleryPanel = useGalleryPanel(activeTab);
|
||||
|
||||
const isGalleryImage = useMemo(() => {
|
||||
return !!imageDTO.board_id;
|
||||
}, [imageDTO]);
|
||||
|
||||
const onClick = useCallback(() => {
|
||||
navigationApi.expandRightPanel();
|
||||
galleryPanel.expand();
|
||||
dispatch(boardIdSelected({ boardId: imageDTO.board_id ?? 'none', selectedImageName: imageDTO.image_name }));
|
||||
}, [dispatch, galleryPanel, imageDTO]);
|
||||
|
||||
return (
|
||||
<MenuItem icon={<PiCrosshair />} onClickCapture={onClick} isDisabled={!isGalleryImage}>
|
||||
{t('boards.locateInGalery')}
|
||||
</MenuItem>
|
||||
);
|
||||
});
|
||||
|
||||
ImageMenuItemLocateInGalery.displayName = 'ImageMenuItemLocateInGalery';
|
||||
@@ -6,6 +6,7 @@ import { ImageMenuItemCopy } from 'features/gallery/components/ImageContextMenu/
|
||||
import { ImageMenuItemDelete } from 'features/gallery/components/ImageContextMenu/ImageMenuItemDelete';
|
||||
import { ImageMenuItemDownload } from 'features/gallery/components/ImageContextMenu/ImageMenuItemDownload';
|
||||
import { ImageMenuItemLoadWorkflow } from 'features/gallery/components/ImageContextMenu/ImageMenuItemLoadWorkflow';
|
||||
import { ImageMenuItemLocateInGalery } from 'features/gallery/components/ImageContextMenu/ImageMenuItemLocateInGalery';
|
||||
import { ImageMenuItemMetadataRecallActionsCanvasGenerateTabs } from 'features/gallery/components/ImageContextMenu/ImageMenuItemMetadataRecallActionsCanvasGenerateTabs';
|
||||
import { ImageMenuItemNewCanvasFromImageSubMenu } from 'features/gallery/components/ImageContextMenu/ImageMenuItemNewCanvasFromImageSubMenu';
|
||||
import { ImageMenuItemNewLayerFromImageSubMenu } from 'features/gallery/components/ImageContextMenu/ImageMenuItemNewLayerFromImageSubMenu';
|
||||
@@ -55,6 +56,7 @@ const SingleSelectionMenuItems = ({ imageDTO }: SingleSelectionMenuItemsProps) =
|
||||
<MenuDivider />
|
||||
<ImageMenuItemChangeBoard />
|
||||
<ImageMenuItemStarUnstar />
|
||||
<ImageMenuItemLocateInGalery />
|
||||
</ImageDTOContextProvider>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -448,6 +448,35 @@ export class NavigationApi {
|
||||
return this.panels.get(key);
|
||||
};
|
||||
|
||||
/**
|
||||
* Expand the left panel in the currently active tab.
|
||||
*
|
||||
* This method will not wait for the panel to be registered.
|
||||
*
|
||||
* @returns True if the panel was expanded, false if it was not found or an error occurred
|
||||
*/
|
||||
expandLeftPanel = (): boolean => {
|
||||
const activeTab = this._app?.activeTab.get() ?? null;
|
||||
if (!activeTab) {
|
||||
log.warn('No active tab found to expand left panel');
|
||||
return false;
|
||||
}
|
||||
const leftPanel = this.getPanel(activeTab, LEFT_PANEL_ID);
|
||||
if (!leftPanel) {
|
||||
log.warn(`Left panel not found in active tab "${activeTab}"`);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(leftPanel instanceof GridviewPanel)) {
|
||||
log.error(`Right panels must be instances of GridviewPanel`);
|
||||
return false;
|
||||
}
|
||||
|
||||
this._expandPanel(leftPanel, LEFT_PANEL_MIN_SIZE_PX);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Toggle the left panel in the currently active tab.
|
||||
*
|
||||
@@ -481,6 +510,35 @@ export class NavigationApi {
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Expand the right panel in the currently active tab.
|
||||
*
|
||||
* This method will not wait for the panel to be registered.
|
||||
*
|
||||
* @returns True if the panel was expanded, false if it was not found or an error occurred
|
||||
*/
|
||||
expandRightPanel = (): boolean => {
|
||||
const activeTab = this._app?.activeTab.get() ?? null;
|
||||
if (!activeTab) {
|
||||
log.warn('No active tab found to expand right panel');
|
||||
return false;
|
||||
}
|
||||
const rightPanel = this.getPanel(activeTab, RIGHT_PANEL_ID);
|
||||
if (!rightPanel) {
|
||||
log.warn(`Right panel not found in active tab "${activeTab}"`);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(rightPanel instanceof GridviewPanel)) {
|
||||
log.error(`Right panels must be instances of GridviewPanel`);
|
||||
return false;
|
||||
}
|
||||
|
||||
this._expandPanel(rightPanel, RIGHT_PANEL_MIN_SIZE_PX);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Toggle the right panel in the currently active tab.
|
||||
*
|
||||
|
||||
@@ -28,11 +28,15 @@ export const useCollapsibleGridviewPanel = (
|
||||
const lastExpandedSizeRef = useRef<number>(0);
|
||||
const collapse = useCallback(() => {
|
||||
const panel = navigationApi.getPanel(tab, panelId);
|
||||
|
||||
if (!panel || !(panel instanceof GridviewPanel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isCollapsed = getIsCollapsed(panel, orientation, collapsedSize);
|
||||
if (isCollapsed) {
|
||||
return;
|
||||
}
|
||||
|
||||
lastExpandedSizeRef.current = orientation === 'vertical' ? panel.height : panel.width;
|
||||
|
||||
if (orientation === 'vertical') {
|
||||
@@ -48,6 +52,11 @@ export const useCollapsibleGridviewPanel = (
|
||||
return;
|
||||
}
|
||||
|
||||
const isCollapsed = getIsCollapsed(panel, orientation, collapsedSize);
|
||||
if (!isCollapsed) {
|
||||
return;
|
||||
}
|
||||
|
||||
let newSize = lastExpandedSizeRef.current || defaultSize;
|
||||
if (minExpandedSize && newSize < minExpandedSize) {
|
||||
newSize = minExpandedSize;
|
||||
@@ -58,7 +67,7 @@ export const useCollapsibleGridviewPanel = (
|
||||
} else {
|
||||
panel.api.setSize({ width: newSize });
|
||||
}
|
||||
}, [defaultSize, minExpandedSize, orientation, panelId, tab]);
|
||||
}, [defaultSize, minExpandedSize, orientation, collapsedSize, panelId, tab]);
|
||||
|
||||
const toggle = useCallback(() => {
|
||||
const panel = navigationApi.getPanel(tab, panelId);
|
||||
@@ -66,6 +75,7 @@ export const useCollapsibleGridviewPanel = (
|
||||
return;
|
||||
}
|
||||
const isCollapsed = getIsCollapsed(panel, orientation, collapsedSize);
|
||||
|
||||
if (isCollapsed) {
|
||||
expand();
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import type { TabName } from 'features/ui/store/uiTypes';
|
||||
|
||||
import {
|
||||
GALLERY_PANEL_DEFAULT_HEIGHT_PX,
|
||||
GALLERY_PANEL_ID,
|
||||
GALLERY_PANEL_MIN_EXPANDED_HEIGHT_PX,
|
||||
GALLERY_PANEL_MIN_HEIGHT_PX,
|
||||
} from './shared';
|
||||
import { useCollapsibleGridviewPanel } from './use-collapsible-gridview-panel';
|
||||
|
||||
export const useGalleryPanel = (tab: TabName) => {
|
||||
return useCollapsibleGridviewPanel(
|
||||
tab,
|
||||
GALLERY_PANEL_ID,
|
||||
'vertical',
|
||||
GALLERY_PANEL_DEFAULT_HEIGHT_PX,
|
||||
GALLERY_PANEL_MIN_HEIGHT_PX,
|
||||
GALLERY_PANEL_MIN_EXPANDED_HEIGHT_PX
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user