Skip to content

Commit 7c08ed8

Browse files
feat(ui): restore all panel hotkeys
1 parent 2f3b2f1 commit 7c08ed8

9 files changed

+200
-336
lines changed

invokeai/frontend/web/src/features/ui/components/AppContent.tsx

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -24,53 +24,9 @@ const onLeftPanelCollapse = (isCollapsed: boolean) => $isLeftPanelOpen.set(!isCo
2424
const onRightPanelCollapse = (isCollapsed: boolean) => $isRightPanelOpen.set(!isCollapsed);
2525

2626
export const AppContent = memo(() => {
27-
// const tab = useAppSelector(selectActiveTab);
2827
const tabIndex = useAppSelector(selectActiveTabIndex);
29-
// const imperativePanelGroupRef = useRef<ImperativePanelGroupHandle>(null);
3028
useDndMonitor();
3129

32-
// const withLeftPanel = useAppSelector(selectWithLeftPanel);
33-
// const leftPanelUsePanelOptions = useMemo<UsePanelOptions>(
34-
// () => ({
35-
// id: 'left-panel',
36-
// minSizePx: LEFT_PANEL_MIN_SIZE_PX,
37-
// defaultSizePx: LEFT_PANEL_MIN_SIZE_PX,
38-
// imperativePanelGroupRef,
39-
// panelGroupDirection: 'horizontal',
40-
// onCollapse: onLeftPanelCollapse,
41-
// }),
42-
// []
43-
// );
44-
// const leftPanel = usePanel(leftPanelUsePanelOptions);
45-
// useRegisteredHotkeys({
46-
// id: 'toggleLeftPanel',
47-
// category: 'app',
48-
// callback: leftPanel.toggle,
49-
// options: { enabled: withLeftPanel },
50-
// dependencies: [leftPanel.toggle, withLeftPanel],
51-
// });
52-
53-
// const withRightPanel = useAppSelector(selectWithRightPanel);
54-
// const rightPanelUsePanelOptions = useMemo<UsePanelOptions>(
55-
// () => ({
56-
// id: 'right-panel',
57-
// minSizePx: RIGHT_PANEL_MIN_SIZE_PX,
58-
// defaultSizePx: RIGHT_PANEL_MIN_SIZE_PX,
59-
// imperativePanelGroupRef,
60-
// panelGroupDirection: 'horizontal',
61-
// onCollapse: onRightPanelCollapse,
62-
// }),
63-
// []
64-
// );
65-
// const rightPanel = usePanel(rightPanelUsePanelOptions);
66-
// useRegisteredHotkeys({
67-
// id: 'toggleRightPanel',
68-
// category: 'app',
69-
// callback: rightPanel.toggle,
70-
// options: { enabled: withRightPanel },
71-
// dependencies: [rightPanel.toggle, withRightPanel],
72-
// });
73-
7430
// useRegisteredHotkeys({
7531
// id: 'resetPanelLayout',
7632
// category: 'app',

invokeai/frontend/web/src/features/ui/components/FloatingLeftPanelButtons.tsx

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { useDeleteAllExceptCurrentQueueItemDialog } from 'features/queue/compone
55
import { InvokeButtonTooltip } from 'features/queue/components/InvokeButtonTooltip/InvokeButtonTooltip';
66
import { useDeleteCurrentQueueItem } from 'features/queue/hooks/useDeleteCurrentQueueItem';
77
import { useInvoke } from 'features/queue/hooks/useInvoke';
8-
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
98
import { useAutoLayoutContext } from 'features/ui/layouts/auto-layout-context';
109
import { memo } from 'react';
1110
import { useTranslation } from 'react-i18next';
@@ -54,11 +53,6 @@ FloatingCanvasLeftPanelButtons.displayName = 'FloatingCanvasLeftPanelButtons';
5453

5554
const ToggleLeftPanelButton = memo(() => {
5655
const { toggleLeftPanel } = useAutoLayoutContext();
57-
useRegisteredHotkeys({
58-
category: 'app',
59-
id: 'toggleLeftPanel',
60-
callback: toggleLeftPanel,
61-
});
6256
const { t } = useTranslation();
6357
return (
6458
<Tooltip label={t('accessibility.toggleLeftPanel')} placement="end">

invokeai/frontend/web/src/features/ui/components/FloatingRightPanelButtons.tsx

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { Flex, IconButton, Tooltip } from '@invoke-ai/ui-library';
2-
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
32
import { useAutoLayoutContext } from 'features/ui/layouts/auto-layout-context';
43
import { memo } from 'react';
54
import { useTranslation } from 'react-i18next';
@@ -17,11 +16,6 @@ FloatingRightPanelButtons.displayName = 'FloatingRightPanelButtons';
1716
const ToggleRightPanelButton = memo(() => {
1817
const { t } = useTranslation();
1918
const { toggleRightPanel } = useAutoLayoutContext();
20-
useRegisteredHotkeys({
21-
category: 'app',
22-
id: 'toggleRightPanel',
23-
callback: toggleRightPanel,
24-
});
2519

2620
return (
2721
<Tooltip label={t('accessibility.toggleRightPanel')} placement="start">
Lines changed: 114 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,106 @@
11
import type { GridviewApi } from 'dockview';
2+
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
23
import type { Atom } from 'nanostores';
34
import type { PropsWithChildren } from 'react';
4-
import { createContext, useContext, useMemo } from 'react';
5+
import { createContext, memo, useCallback, useContext, useMemo } from 'react';
6+
7+
import { LEFT_PANEL_ID, LEFT_PANEL_MIN_SIZE_PX, RIGHT_PANEL_ID, RIGHT_PANEL_MIN_SIZE_PX } from './shared';
58

69
type AutoLayoutContextValue = {
710
$api: Atom<GridviewApi | null>;
811
toggleLeftPanel: () => void;
912
toggleRightPanel: () => void;
13+
toggleBothPanels: () => void;
14+
resetPanels: () => void;
1015
};
1116

1217
const AutoLayoutContext = createContext<AutoLayoutContextValue | null>(null);
1318

14-
export const AutoLayoutProvider = (props: PropsWithChildren<AutoLayoutContextValue>) => {
19+
const expandPanel = (api: GridviewApi, panelId: string, width: number) => {
20+
const panel = api.getPanel(panelId);
21+
if (!panel) {
22+
return;
23+
}
24+
panel.api.setConstraints({ maximumWidth: Number.MAX_SAFE_INTEGER, minimumWidth: width });
25+
panel.api.setSize({ width: width });
26+
};
27+
28+
const collapsePanel = (api: GridviewApi, panelId: string) => {
29+
const panel = api.getPanel(panelId);
30+
if (!panel) {
31+
return;
32+
}
33+
panel.api.setConstraints({ maximumWidth: 0, minimumWidth: 0 });
34+
panel.api.setSize({ width: 0 });
35+
};
36+
37+
const getIsCollapsed = (api: GridviewApi, panelId: string) => {
38+
const panel = api.getPanel(panelId);
39+
if (!panel) {
40+
return true; // ??
41+
}
42+
return panel.maximumWidth === 0;
43+
};
44+
45+
export const AutoLayoutProvider = (props: PropsWithChildren<{ $api: Atom<GridviewApi | null> }>) => {
46+
const toggleLeftPanel = useCallback(() => {
47+
const api = props.$api.get();
48+
if (!api) {
49+
return;
50+
}
51+
if (getIsCollapsed(api, LEFT_PANEL_ID)) {
52+
expandPanel(api, LEFT_PANEL_ID, LEFT_PANEL_MIN_SIZE_PX);
53+
} else {
54+
collapsePanel(api, LEFT_PANEL_ID);
55+
}
56+
}, [props.$api]);
57+
58+
const toggleRightPanel = useCallback(() => {
59+
const api = props.$api.get();
60+
if (!api) {
61+
return;
62+
}
63+
if (getIsCollapsed(api, RIGHT_PANEL_ID)) {
64+
expandPanel(api, RIGHT_PANEL_ID, RIGHT_PANEL_MIN_SIZE_PX);
65+
} else {
66+
collapsePanel(api, RIGHT_PANEL_ID);
67+
}
68+
}, [props.$api]);
69+
70+
const toggleBothPanels = useCallback(() => {
71+
const api = props.$api.get();
72+
if (!api) {
73+
return;
74+
}
75+
requestAnimationFrame(() => {
76+
if (getIsCollapsed(api, RIGHT_PANEL_ID) || getIsCollapsed(api, LEFT_PANEL_ID)) {
77+
expandPanel(api, LEFT_PANEL_ID, LEFT_PANEL_MIN_SIZE_PX);
78+
expandPanel(api, RIGHT_PANEL_ID, RIGHT_PANEL_MIN_SIZE_PX);
79+
} else {
80+
collapsePanel(api, LEFT_PANEL_ID);
81+
collapsePanel(api, RIGHT_PANEL_ID);
82+
}
83+
});
84+
}, [props.$api]);
85+
86+
const resetPanels = useCallback(() => {
87+
const api = props.$api.get();
88+
if (!api) {
89+
return;
90+
}
91+
expandPanel(api, LEFT_PANEL_ID, LEFT_PANEL_MIN_SIZE_PX);
92+
expandPanel(api, RIGHT_PANEL_ID, RIGHT_PANEL_MIN_SIZE_PX);
93+
}, [props.$api]);
94+
1595
const value = useMemo<AutoLayoutContextValue>(
1696
() => ({
1797
$api: props.$api,
18-
toggleLeftPanel: props.toggleLeftPanel,
19-
toggleRightPanel: props.toggleRightPanel,
98+
toggleLeftPanel,
99+
toggleRightPanel,
100+
toggleBothPanels,
101+
resetPanels,
20102
}),
21-
[props.$api, props.toggleLeftPanel, props.toggleRightPanel]
103+
[props.$api, resetPanels, toggleBothPanels, toggleLeftPanel, toggleRightPanel]
22104
);
23105
return <AutoLayoutContext.Provider value={value}>{props.children}</AutoLayoutContext.Provider>;
24106
};
@@ -30,3 +112,30 @@ export const useAutoLayoutContext = () => {
30112
}
31113
return value;
32114
};
115+
116+
export const PanelHotkeysLogical = memo(() => {
117+
const { toggleBothPanels, resetPanels, toggleLeftPanel, toggleRightPanel } = useAutoLayoutContext();
118+
useRegisteredHotkeys({
119+
category: 'app',
120+
id: 'toggleLeftPanel',
121+
callback: toggleLeftPanel,
122+
});
123+
useRegisteredHotkeys({
124+
category: 'app',
125+
id: 'toggleRightPanel',
126+
callback: toggleRightPanel,
127+
});
128+
useRegisteredHotkeys({
129+
category: 'app',
130+
id: 'resetPanelLayout',
131+
callback: resetPanels,
132+
});
133+
useRegisteredHotkeys({
134+
category: 'app',
135+
id: 'togglePanels',
136+
callback: toggleBothPanels,
137+
});
138+
139+
return null;
140+
});
141+
PanelHotkeysLogical.displayName = 'PanelHotkeysLogical';

invokeai/frontend/web/src/features/ui/layouts/canvas-tab-auto-layout.tsx

Lines changed: 14 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,24 @@ import { BoardsPanel } from 'features/gallery/components/BoardsListPanelContent'
66
import { GalleryPanel } from 'features/gallery/components/Gallery';
77
import { GenerationProgressPanel } from 'features/gallery/components/ImageViewer/GenerationProgressPanel';
88
import { ImageViewerPanel } from 'features/gallery/components/ImageViewer/ImageViewerPanel';
9-
import { FloatingLeftPanelButtons } from 'features/ui/components/FloatingLeftPanelButtons';
9+
import { FloatingCanvasLeftPanelButtons } from 'features/ui/components/FloatingLeftPanelButtons';
1010
import { FloatingRightPanelButtons } from 'features/ui/components/FloatingRightPanelButtons';
11-
import { AutoLayoutProvider } from 'features/ui/layouts/auto-layout-context';
11+
import { AutoLayoutProvider, PanelHotkeysLogical } from 'features/ui/layouts/auto-layout-context';
1212
import { TabWithoutCloseButton } from 'features/ui/layouts/TabWithoutCloseButton';
13-
import { LEFT_PANEL_MIN_SIZE_PX, RIGHT_PANEL_MIN_SIZE_PX } from 'features/ui/store/uiSlice';
1413
import { dockviewTheme } from 'features/ui/styles/theme';
1514
import { atom } from 'nanostores';
1615
import { memo, useCallback, useRef, useState } from 'react';
1716

1817
import { CanvasTabLeftPanel } from './CanvasTabLeftPanel';
1918
import { CanvasWorkspacePanel } from './CanvasWorkspacePanel';
20-
import { useOnFirstVisible } from './use-on-first-visible';
19+
import {
20+
LEFT_PANEL_ID,
21+
LEFT_PANEL_MIN_SIZE_PX,
22+
MAIN_PANEL_ID,
23+
RIGHT_PANEL_ID,
24+
RIGHT_PANEL_MIN_SIZE_PX,
25+
} from './shared';
26+
import { useResizeMainPanelOnFirstVisit } from './use-on-first-visible';
2127

2228
const LAUNCHPAD_PANEL_ID = 'launchpad';
2329
const WORKSPACE_PANEL_ID = 'workspace';
@@ -97,8 +103,9 @@ const MainPanel = memo(() => {
97103
onReady={onReadyMainPanel}
98104
theme={dockviewTheme}
99105
/>
100-
<FloatingLeftPanelButtons />
106+
<FloatingCanvasLeftPanelButtons />
101107
<FloatingRightPanelButtons />
108+
<PanelHotkeysLogical />
102109
</>
103110
);
104111
});
@@ -160,10 +167,6 @@ const RightPanel = memo(() => {
160167
});
161168
RightPanel.displayName = 'RightPanel';
162169

163-
const LEFT_PANEL_ID = 'left';
164-
const MAIN_PANEL_ID = 'main';
165-
const RIGHT_PANEL_ID = 'right';
166-
167170
export const rootComponents: IGridviewReactProps['components'] = {
168171
[LEFT_PANEL_ID]: CanvasTabLeftPanel,
169172
[MAIN_PANEL_ID]: MainPanel,
@@ -209,69 +212,10 @@ export const CanvasTabAutoLayout = memo(() => {
209212
},
210213
[$api]
211214
);
212-
const resizeMainPanelOnFirstVisible = useCallback(() => {
213-
const api = $api.get();
214-
if (!api) {
215-
return;
216-
}
217-
const mainPanel = api.getPanel(MAIN_PANEL_ID);
218-
if (!mainPanel) {
219-
return;
220-
}
221-
if (mainPanel.width !== 0) {
222-
return;
223-
}
224-
let count = 0;
225-
const setSize = () => {
226-
if (count++ > 50) {
227-
return;
228-
}
229-
mainPanel.api.setSize({ width: Number.MAX_SAFE_INTEGER });
230-
if (mainPanel.width === 0) {
231-
requestAnimationFrame(setSize);
232-
return;
233-
}
234-
};
235-
setSize();
236-
}, [$api]);
237-
useOnFirstVisible(ref, resizeMainPanelOnFirstVisible);
238-
const toggleLeftPanel = useCallback(() => {
239-
const api = $api.get();
240-
if (!api) {
241-
return;
242-
}
243-
const left = api.getPanel(LEFT_PANEL_ID);
244-
if (!left) {
245-
return;
246-
}
247-
if (left.maximumWidth === 0) {
248-
left.api.setConstraints({ maximumWidth: Number.MAX_SAFE_INTEGER, minimumWidth: LEFT_PANEL_MIN_SIZE_PX });
249-
left.api.setSize({ width: LEFT_PANEL_MIN_SIZE_PX });
250-
} else {
251-
left.api.setConstraints({ maximumWidth: 0, minimumWidth: 0 });
252-
left.api.setSize({ width: 0 });
253-
}
254-
}, [$api]);
255-
const toggleRightPanel = useCallback(() => {
256-
const api = $api.get();
257-
if (!api) {
258-
return;
259-
}
260-
const right = api.getPanel(RIGHT_PANEL_ID);
261-
if (!right) {
262-
return;
263-
}
264-
if (right.maximumWidth === 0) {
265-
right.api.setConstraints({ maximumWidth: Number.MAX_SAFE_INTEGER, minimumWidth: RIGHT_PANEL_MIN_SIZE_PX });
266-
right.api.setSize({ width: RIGHT_PANEL_MIN_SIZE_PX });
267-
} else {
268-
right.api.setConstraints({ maximumWidth: 0, minimumWidth: 0 });
269-
right.api.setSize({ width: 0 });
270-
}
271-
}, [$api]);
215+
useResizeMainPanelOnFirstVisit($api, ref);
272216

273217
return (
274-
<AutoLayoutProvider $api={$api} toggleLeftPanel={toggleLeftPanel} toggleRightPanel={toggleRightPanel}>
218+
<AutoLayoutProvider $api={$api}>
275219
<GridviewReact
276220
ref={ref}
277221
className="dockview-theme-invoke"

0 commit comments

Comments
 (0)