You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
455 lines
16 KiB
TypeScript
455 lines
16 KiB
TypeScript
import {
|
|
Menu,
|
|
app,
|
|
dialog,
|
|
BrowserWindow,
|
|
MenuItem,
|
|
WebContents,
|
|
MenuItemConstructorOptions,
|
|
} from "electron";
|
|
import * as fs from "fs";
|
|
import * as Utils from "../common/Utils";
|
|
import MainEventType from "../common/MainEventType";
|
|
import { MainProcess } from "./MainProcess";
|
|
import Settings from "./Settings";
|
|
|
|
const packageConf = require("../package.json");
|
|
|
|
export default class AppMenu {
|
|
private mainProcess: MainProcess;
|
|
private mainWindow: BrowserWindow;
|
|
private webContents: WebContents;
|
|
private settings: Settings;
|
|
|
|
constructor(mainProcess: MainProcess) {
|
|
this.mainProcess = mainProcess;
|
|
this.mainWindow = mainProcess.mainWindow;
|
|
this.webContents = mainProcess.mainWindow.webContents;
|
|
this.settings = mainProcess.settings;
|
|
}
|
|
|
|
createMenu() {
|
|
const menu: Menu = new Menu();
|
|
menu.append(this.createFileMenu());
|
|
menu.append(this.createEditMenu());
|
|
menu.append(this.createNodeMenu());
|
|
menu.append(this.createWorkspaceMenu());
|
|
menu.append(this.createToolsMenu());
|
|
return menu;
|
|
}
|
|
|
|
private createFileMenu() {
|
|
const fileItems: MenuItemConstructorOptions[] = [];
|
|
for (let path of this.settings.recentFiles) {
|
|
fileItems.push({
|
|
label: path,
|
|
click: () => {
|
|
console.log("open recent file", path);
|
|
},
|
|
});
|
|
}
|
|
|
|
return new MenuItem({
|
|
label: "行为树",
|
|
submenu: [
|
|
{
|
|
label: "新建",
|
|
accelerator: "ctrl+n",
|
|
click: () => {
|
|
(async () => {
|
|
const res = await dialog.showSaveDialog({
|
|
properties: ["showOverwriteConfirmation"],
|
|
filters: [{ name: "Json", extensions: ["json"] }],
|
|
});
|
|
if (!res.canceled) {
|
|
const path = res.filePath;
|
|
fs.writeFileSync(
|
|
path,
|
|
JSON.stringify(Utils.createNewTree(path), null, 2)
|
|
);
|
|
this.webContents.send(MainEventType.CREATE_TREE, path);
|
|
}
|
|
})();
|
|
},
|
|
},
|
|
{
|
|
label: "打开文件",
|
|
accelerator: "Ctrl+O",
|
|
click: () => {
|
|
(async () => {
|
|
const res = await dialog.showOpenDialog({
|
|
properties: ["openFile"],
|
|
filters: [{ name: "Json", extensions: ["json"] }],
|
|
});
|
|
if (res.filePaths.length > 0) {
|
|
const path = res.filePaths[0];
|
|
if (this.settings.recentFiles.indexOf(path) < 0) {
|
|
this.settings.recentFiles.unshift(path);
|
|
this.settings.save();
|
|
this.mainProcess.rebuildMenu();
|
|
}
|
|
this.webContents.send(MainEventType.OPEN_FILE, path);
|
|
}
|
|
})();
|
|
},
|
|
},
|
|
{ type: "separator" },
|
|
{
|
|
label: "最近打开",
|
|
submenu: fileItems,
|
|
},
|
|
|
|
{ type: "separator" },
|
|
{
|
|
label: "保存",
|
|
accelerator: "ctrl+s",
|
|
click: () => {
|
|
this.webContents.send(MainEventType.SAVE);
|
|
},
|
|
},
|
|
{
|
|
label: "全部保存",
|
|
accelerator: "ctrl+shift+s",
|
|
click: () => {
|
|
this.webContents.send(MainEventType.SAVE_ALL);
|
|
},
|
|
},
|
|
{
|
|
label: "合并导出Json",
|
|
click: () => {
|
|
(async () => {
|
|
const res = await dialog.showSaveDialog({
|
|
properties: ["showOverwriteConfirmation"],
|
|
filters: [{ name: "Json", extensions: ["json"] }],
|
|
});
|
|
if (res.filePath) {
|
|
const curWorkspace = this.settings.curWorkspace;
|
|
curWorkspace.writeAllTrees(res.filePath, (err) => {
|
|
const msg = err ? err : "导出成功";
|
|
dialog.showMessageBox({
|
|
type: "info",
|
|
buttons: ["ok"],
|
|
message: msg,
|
|
});
|
|
});
|
|
}
|
|
})();
|
|
},
|
|
},
|
|
],
|
|
});
|
|
}
|
|
|
|
private createEditMenu() {
|
|
return new MenuItem({
|
|
label: "编辑",
|
|
submenu: [
|
|
{
|
|
label: "撤销",
|
|
accelerator: "ctrl+z",
|
|
click: () => {
|
|
this.webContents.send(MainEventType.UNDO);
|
|
}
|
|
},
|
|
{
|
|
label: "恢复",
|
|
accelerator: "ctrl+y",
|
|
click: () => {
|
|
this.webContents.send(MainEventType.REDO);
|
|
}
|
|
},
|
|
{ type: "separator" },
|
|
{
|
|
label: "新建节点",
|
|
accelerator: "insert",
|
|
click: () => {
|
|
this.webContents.send(MainEventType.CREATE_NODE, "unknow");
|
|
},
|
|
},
|
|
{
|
|
label: "删除节点",
|
|
accelerator: "delete",
|
|
click: () => {
|
|
this.webContents.send(MainEventType.DELETE_NODE);
|
|
},
|
|
},
|
|
{ type: "separator" },
|
|
{
|
|
label: "复制节点",
|
|
accelerator: "ctrl+c",
|
|
role: "copy",
|
|
click: () => {
|
|
this.webContents.send(MainEventType.COPY_NODE);
|
|
},
|
|
},
|
|
{
|
|
label: "粘贴节点",
|
|
accelerator: "ctrl+v",
|
|
click: () => {
|
|
this.webContents.send(MainEventType.PASTE_NODE);
|
|
},
|
|
},
|
|
]
|
|
})
|
|
}
|
|
|
|
private createWorkspaceMenu() {
|
|
const openWorkspace = (path: string) => {
|
|
const curWorkspace = this.settings.curWorkspace;
|
|
curWorkspace.setFilepath(path);
|
|
curWorkspace.load();
|
|
this.settings.pushRecentWorkspace(path);
|
|
this.mainProcess.rebuildMenu();
|
|
this.webContents.send(
|
|
MainEventType.OPEN_DIR,
|
|
curWorkspace.getWorkdir(),
|
|
curWorkspace.getFilepath()
|
|
);
|
|
};
|
|
const saveToNewPath = () => {
|
|
(async () => {
|
|
const res = await dialog.showSaveDialog({
|
|
properties: ["showOverwriteConfirmation"],
|
|
filters: [{ name: "Json", extensions: ["json"] }],
|
|
});
|
|
if (!res.canceled) {
|
|
this.settings.curWorkspace.setFilepath(res.filePath);
|
|
this.settings.curWorkspace.save();
|
|
openWorkspace(res.filePath);
|
|
}
|
|
})();
|
|
};
|
|
const recentItems: MenuItemConstructorOptions[] = [];
|
|
for (let path of this.settings.recentWorkspaces) {
|
|
recentItems.push({
|
|
label: path,
|
|
click: () => {
|
|
console.log("open recent workspace", path);
|
|
openWorkspace(path);
|
|
},
|
|
});
|
|
}
|
|
return new MenuItem({
|
|
label: "工作区",
|
|
submenu: [
|
|
{
|
|
label: "打开",
|
|
click: () => {
|
|
(async () => {
|
|
const res = await dialog.showOpenDialog({
|
|
properties: ["openFile"],
|
|
filters: [{ name: "Json", extensions: ["json"] }],
|
|
});
|
|
if (res.filePaths.length > 0) {
|
|
openWorkspace(res.filePaths[0]);
|
|
}
|
|
})();
|
|
},
|
|
},
|
|
{
|
|
label: "保存",
|
|
click: () => {
|
|
if (this.settings.curWorkspace.getFilepath()) {
|
|
this.settings.curWorkspace.save();
|
|
} else {
|
|
saveToNewPath();
|
|
}
|
|
},
|
|
},
|
|
{
|
|
label: "另存为",
|
|
click: () => {
|
|
saveToNewPath();
|
|
},
|
|
},
|
|
{
|
|
label: "刷新",
|
|
accelerator: "F5",
|
|
click: () => {
|
|
console.log("reload workspace");
|
|
openWorkspace(this.settings.curWorkspace.getFilepath());
|
|
},
|
|
},
|
|
{
|
|
label: "最近打开",
|
|
submenu: recentItems,
|
|
},
|
|
{ type: "separator" },
|
|
{
|
|
label: "打开目录",
|
|
accelerator: "Ctrl+Shift+O",
|
|
click: () => {
|
|
if (!this.settings.curWorkspace.getNodeConfPath()) {
|
|
dialog.showErrorBox("警告", "请先指定节点定义配置!");
|
|
return;
|
|
}
|
|
(async () => {
|
|
const res = await dialog.showOpenDialog({
|
|
properties: ["openDirectory"],
|
|
});
|
|
if (res.filePaths.length > 0) {
|
|
const curWorkspace = this.settings.curWorkspace;
|
|
const path = res.filePaths[0];
|
|
curWorkspace.setWorkdir(path);
|
|
curWorkspace.save();
|
|
this.webContents.send(
|
|
MainEventType.OPEN_DIR,
|
|
path,
|
|
curWorkspace.getFilepath()
|
|
);
|
|
}
|
|
})();
|
|
},
|
|
},
|
|
{
|
|
label: "节点定义",
|
|
submenu: [
|
|
{
|
|
label: "选择文件",
|
|
click: () => {
|
|
(async () => {
|
|
const res = await dialog.showOpenDialog({
|
|
properties: ["openFile"],
|
|
filters: [{ name: "Json", extensions: ["json"] }],
|
|
});
|
|
if (res.filePaths.length > 0) {
|
|
const nodeConfigPath = res.filePaths[0];
|
|
this.settings.curWorkspace.setNodeConfPath(nodeConfigPath);
|
|
this.mainProcess.rebuildMenu();
|
|
}
|
|
})();
|
|
},
|
|
},
|
|
{ type: "separator" },
|
|
{ label: this.settings.nodeConfPath },
|
|
],
|
|
},
|
|
{ type: "separator" },
|
|
{
|
|
label: "关闭",
|
|
click: () => {
|
|
app.quit();
|
|
},
|
|
},
|
|
],
|
|
});
|
|
}
|
|
|
|
private createToolsMenu() {
|
|
const serverItems: MenuItemConstructorOptions[] = [];
|
|
const curServerName = this.settings.serverName;
|
|
for (let model of this.settings.curWorkspace.getServers()) {
|
|
serverItems.push({
|
|
label: `${model.name} ${model.host}`,
|
|
type: 'checkbox',
|
|
checked: curServerName == model.name,
|
|
click: () => {
|
|
this.settings.serverName = model.name;
|
|
this.mainProcess.rebuildMenu();
|
|
}
|
|
})
|
|
}
|
|
return new MenuItem({
|
|
label: "开发工具",
|
|
submenu: [
|
|
{
|
|
label: "热更",
|
|
accelerator: "Ctrl+R",
|
|
click: () => {
|
|
this.webContents.send(MainEventType.RELOAD_SERVER);
|
|
}
|
|
},
|
|
{
|
|
label: "联调服务器",
|
|
submenu: serverItems,
|
|
},
|
|
{
|
|
label: "批处理脚本",
|
|
click: () => {
|
|
(async () => {
|
|
const res = await dialog.showOpenDialog({
|
|
properties: ["openFile"],
|
|
filters: [{ name: "Javascript", extensions: ["js"] }],
|
|
});
|
|
if (res.filePaths.length > 0) {
|
|
this.webContents.send(MainEventType.BATCH_EXEC, res.filePaths[0]);
|
|
}
|
|
})();
|
|
}
|
|
},
|
|
{
|
|
type: 'separator',
|
|
},
|
|
{
|
|
label: "打开控制台",
|
|
accelerator: "Ctrl+Shift+I",
|
|
click: (_, browserWindow) => {
|
|
browserWindow.webContents.toggleDevTools();
|
|
},
|
|
},
|
|
{
|
|
label: "重载编辑器",
|
|
click: (_, browserWindow) => {
|
|
browserWindow.reload();
|
|
},
|
|
},
|
|
{
|
|
type: 'separator',
|
|
},
|
|
{
|
|
label: `当前版本:${packageConf.version}`
|
|
}
|
|
],
|
|
});
|
|
}
|
|
|
|
private createNodeMenu() {
|
|
const classifyItems: MenuItemConstructorOptions[] = [];
|
|
const map: { [key: string]: MenuItemConstructorOptions } = {};
|
|
for (let t of this.settings.nodeClassify) {
|
|
let item: MenuItemConstructorOptions = {
|
|
id: t.classify,
|
|
label: `${t.classify}(${t.desc})`,
|
|
submenu: [],
|
|
};
|
|
classifyItems.push(item);
|
|
map[t.classify] = item;
|
|
}
|
|
const other: MenuItemConstructorOptions = {
|
|
id: "other",
|
|
label: "其它",
|
|
submenu: [],
|
|
};
|
|
var hasOther = false;
|
|
|
|
for (let node of this.settings.nodeConfig) {
|
|
const item: MenuItemConstructorOptions = {
|
|
label: `${node.name}(${node.desc})`,
|
|
click: () => {
|
|
console.log("create node", node.name);
|
|
this.webContents.send(MainEventType.CREATE_NODE, node.name);
|
|
},
|
|
};
|
|
let typeItem = map[node.type];
|
|
if (!typeItem) {
|
|
typeItem = other;
|
|
hasOther = true;
|
|
}
|
|
if (typeItem.submenu instanceof Menu) {
|
|
console.log("typeItem.submenu error", typeItem);
|
|
} else {
|
|
typeItem.submenu.push(item);
|
|
}
|
|
}
|
|
|
|
if (hasOther) {
|
|
classifyItems.push(other);
|
|
}
|
|
|
|
return new MenuItem({
|
|
label: "新建节点",
|
|
submenu: classifyItems,
|
|
});
|
|
}
|
|
}
|