waveterm/emain/menu.ts

336 lines
9.5 KiB
TypeScript

// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import { waveEventSubscribe } from "@/app/store/wps";
import { RpcApi } from "@/app/store/wshclientapi";
import * as electron from "electron";
import { fireAndForget } from "../frontend/util/util";
import { clearTabCache } from "./emain-tabview";
import {
createNewWaveWindow,
createWorkspace,
focusedWaveWindow,
relaunchBrowserWindows,
WaveBrowserWindow,
} from "./emain-window";
import { ElectronWshClient } from "./emain-wsh";
import { unamePlatform } from "./platform";
import { updater } from "./updater";
type AppMenuCallbacks = {
createNewWaveWindow: () => Promise<void>;
relaunchBrowserWindows: () => Promise<void>;
};
function getWindowWebContents(window: electron.BaseWindow): electron.WebContents {
if (window == null) {
return null;
}
if (window instanceof electron.BaseWindow) {
const waveWin = window as WaveBrowserWindow;
if (waveWin.activeTabView) {
return waveWin.activeTabView.webContents;
}
return null;
}
return null;
}
async function getWorkspaceMenu(): Promise<Electron.MenuItemConstructorOptions[]> {
const workspaceList = await RpcApi.WorkspaceListCommand(ElectronWshClient);
console.log("workspaceList:", workspaceList);
const workspaceMenu: Electron.MenuItemConstructorOptions[] = [
{
label: "Create New Workspace",
click: (_, window) => {
const ww = window as WaveBrowserWindow;
fireAndForget(() => createWorkspace(ww));
},
},
];
function getWorkspaceSwitchAccelerator(i: number): string {
if (i < 10) {
if (i == 9) {
i = 0;
} else {
i++;
}
return unamePlatform == "darwin" ? `Command+Control+${i}` : `Alt+Control+${i}`;
}
}
workspaceList?.length &&
workspaceMenu.push(
{ type: "separator" },
...workspaceList.map<Electron.MenuItemConstructorOptions>((workspace, i) => {
return {
label: `Switch to ${workspace.workspacedata.name} (${workspace.workspacedata.oid.slice(0, 5)})`,
click: (_, window) => {
const ww = window as WaveBrowserWindow;
ww.switchWorkspace(workspace.workspacedata.oid);
},
accelerator: getWorkspaceSwitchAccelerator(i),
};
})
);
return workspaceMenu;
}
async function getAppMenu(callbacks: AppMenuCallbacks): Promise<Electron.Menu> {
const fileMenu: Electron.MenuItemConstructorOptions[] = [
{
label: "New Window",
accelerator: "CommandOrControl+Shift+N",
click: () => fireAndForget(callbacks.createNewWaveWindow),
},
{
role: "close",
accelerator: "", // clear the accelerator
click: () => {
focusedWaveWindow?.close();
},
},
];
const appMenu: Electron.MenuItemConstructorOptions[] = [
{
label: "About Wave Terminal",
click: (_, window) => {
getWindowWebContents(window)?.send("menu-item-about");
},
},
{
label: "Check for Updates",
click: () => {
fireAndForget(() => updater?.checkForUpdates(true));
},
},
{
type: "separator",
},
];
if (unamePlatform === "darwin") {
appMenu.push(
{
role: "services",
},
{
type: "separator",
},
{
role: "hide",
},
{
role: "hideOthers",
},
{
type: "separator",
}
);
}
appMenu.push({
role: "quit",
});
const editMenu: Electron.MenuItemConstructorOptions[] = [
{
role: "undo",
accelerator: unamePlatform === "darwin" ? "Command+Z" : "",
},
{
role: "redo",
accelerator: unamePlatform === "darwin" ? "Command+Shift+Z" : "",
},
{
type: "separator",
},
{
role: "cut",
accelerator: unamePlatform === "darwin" ? "Command+X" : "",
},
{
role: "copy",
accelerator: unamePlatform === "darwin" ? "Command+C" : "",
},
{
role: "paste",
accelerator: unamePlatform === "darwin" ? "Command+V" : "",
},
{
role: "pasteAndMatchStyle",
accelerator: unamePlatform === "darwin" ? "Command+Shift+V" : "",
},
{
role: "delete",
},
{
role: "selectAll",
accelerator: unamePlatform === "darwin" ? "Command+A" : "",
},
];
const devToolsAccel = unamePlatform === "darwin" ? "Option+Command+I" : "Alt+Shift+I";
const viewMenu: Electron.MenuItemConstructorOptions[] = [
{
label: "Reload Tab",
accelerator: "Shift+CommandOrControl+R",
click: (_, window) => {
getWindowWebContents(window)?.reloadIgnoringCache();
},
},
{
label: "Relaunch All Windows",
click: () => {
callbacks.relaunchBrowserWindows();
},
},
{
label: "Clear Tab Cache",
click: () => {
clearTabCache();
},
},
{
label: "Toggle DevTools",
accelerator: devToolsAccel,
click: (_, window) => {
let wc = getWindowWebContents(window);
wc?.toggleDevTools();
},
},
{
type: "separator",
},
{
label: "Reset Zoom",
accelerator: "CommandOrControl+0",
click: (_, window) => {
getWindowWebContents(window)?.setZoomFactor(1);
},
},
{
label: "Zoom In",
accelerator: "CommandOrControl+=",
click: (_, window) => {
const wc = getWindowWebContents(window);
if (wc == null) {
return;
}
if (wc.getZoomFactor() >= 5) {
return;
}
wc.setZoomFactor(wc.getZoomFactor() + 0.2);
},
},
{
label: "Zoom In (hidden)",
accelerator: "CommandOrControl+Shift+=",
click: (_, window) => {
const wc = getWindowWebContents(window);
if (wc == null) {
return;
}
if (wc.getZoomFactor() >= 5) {
return;
}
wc.setZoomFactor(wc.getZoomFactor() + 0.2);
},
visible: false,
acceleratorWorksWhenHidden: true,
},
{
label: "Zoom Out",
accelerator: "CommandOrControl+-",
click: (_, window) => {
const wc = getWindowWebContents(window);
if (wc == null) {
return;
}
if (wc.getZoomFactor() <= 0.2) {
return;
}
wc.setZoomFactor(wc.getZoomFactor() - 0.2);
},
},
{
label: "Zoom Out (hidden)",
accelerator: "CommandOrControl+Shift+-",
click: (_, window) => {
const wc = getWindowWebContents(window);
if (wc == null) {
return;
}
if (wc.getZoomFactor() <= 0.2) {
return;
}
wc.setZoomFactor(wc.getZoomFactor() - 0.2);
},
visible: false,
acceleratorWorksWhenHidden: true,
},
{
type: "separator",
},
{
role: "togglefullscreen",
},
];
const workspaceMenu = await getWorkspaceMenu();
const windowMenu: Electron.MenuItemConstructorOptions[] = [
{ role: "minimize", accelerator: "" },
{ role: "zoom" },
{ type: "separator" },
{ role: "front" },
{ type: "separator" },
{ role: "window" },
];
const menuTemplate: Electron.MenuItemConstructorOptions[] = [
{
role: "appMenu",
submenu: appMenu,
},
{
role: "fileMenu",
submenu: fileMenu,
},
{
role: "editMenu",
submenu: editMenu,
},
{
role: "viewMenu",
submenu: viewMenu,
},
{
label: "Workspace",
id: "workspace-menu",
submenu: workspaceMenu,
},
{
role: "windowMenu",
submenu: windowMenu,
},
];
return electron.Menu.buildFromTemplate(menuTemplate);
}
export function instantiateAppMenu(): Promise<electron.Menu> {
return getAppMenu({
createNewWaveWindow,
relaunchBrowserWindows,
});
}
export function makeAppMenu() {
fireAndForget(async () => {
const menu = await instantiateAppMenu();
electron.Menu.setApplicationMenu(menu);
});
}
waveEventSubscribe({
eventType: "workspace:update",
handler: makeAppMenu,
});
export { getAppMenu };