undo & redo
This commit is contained in:
1 parent
8c6991afb3
commit
d87cba3622
6 files changed
+75
-9
No files matched your search
@@ -53,8 +53,6 @@ npm run dist # 编译exe可执行文件
|
|||||||
+ js/ts版本 计划中。
|
+ js/ts版本 计划中。
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
+ 历史记录(撤销/恢复)
|
|
||||||
+ 资源面板支持树型结构
|
|
||||||
+ 右键菜单
|
+ 右键菜单
|
||||||
|
|
||||||
## About
|
## About
|
||||||
|
|||||||
@@ -10,4 +10,6 @@ export default {
|
|||||||
SAVE: "SAVE",
|
SAVE: "SAVE",
|
||||||
SAVE_ALL: "SAVE_ALL",
|
SAVE_ALL: "SAVE_ALL",
|
||||||
RELOAD_SERVER: "RELOAD_SERVER",
|
RELOAD_SERVER: "RELOAD_SERVER",
|
||||||
|
UNDO: "UNDO",
|
||||||
|
REDO: "REDO",
|
||||||
};
|
};
|
||||||
+26
-3
@@ -28,9 +28,10 @@ export default class AppMenu {
|
|||||||
|
|
||||||
createMenu() {
|
createMenu() {
|
||||||
const menu: Menu = new Menu();
|
const menu: Menu = new Menu();
|
||||||
menu.append(this.createWorkspaceMenu());
|
|
||||||
menu.append(this.createFileMenu());
|
menu.append(this.createFileMenu());
|
||||||
|
menu.append(this.createEditMenu());
|
||||||
menu.append(this.createNodeMenu());
|
menu.append(this.createNodeMenu());
|
||||||
|
menu.append(this.createWorkspaceMenu());
|
||||||
menu.append(this.createToolsMenu());
|
menu.append(this.createToolsMenu());
|
||||||
return menu;
|
return menu;
|
||||||
}
|
}
|
||||||
@@ -133,6 +134,28 @@ export default class AppMenu {
|
|||||||
})();
|
})();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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" },
|
{ type: "separator" },
|
||||||
{
|
{
|
||||||
label: "新建节点",
|
label: "新建节点",
|
||||||
@@ -164,8 +187,8 @@ export default class AppMenu {
|
|||||||
this.webContents.send(MainEventType.PASTE_NODE);
|
this.webContents.send(MainEventType.PASTE_NODE);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
]
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private createWorkspaceMenu() {
|
private createWorkspaceMenu() {
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "behavior3editor",
|
"name": "behavior3editor",
|
||||||
"version": "0.1.3",
|
"version": "0.1.4",
|
||||||
"description": "行为树编辑器",
|
"description": "行为树编辑器",
|
||||||
"main": "./dist/main.js",
|
"main": "./dist/main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import Settings from "../../main-process/Settings";
|
|||||||
|
|
||||||
import "./Editor.css";
|
import "./Editor.css";
|
||||||
import { clipboard } from "electron";
|
import { clipboard } from "electron";
|
||||||
|
import { TreeGraphData } from "@antv/g6/lib/types";
|
||||||
|
|
||||||
export interface EditorProps {
|
export interface EditorProps {
|
||||||
filepath: string;
|
filepath: string;
|
||||||
@@ -35,6 +36,8 @@ export default class Editor extends React.Component<EditorProps, EditorState> {
|
|||||||
private dragSrcId: string;
|
private dragSrcId: string;
|
||||||
private dragDstId: string;
|
private dragDstId: string;
|
||||||
private autoId: number;
|
private autoId: number;
|
||||||
|
private undoStack: BehaviorNodeModel[] = [];
|
||||||
|
private redoStack: BehaviorNodeModel[] = [];
|
||||||
|
|
||||||
constructor(props: EditorProps) {
|
constructor(props: EditorProps) {
|
||||||
super(props);
|
super(props);
|
||||||
@@ -219,6 +222,7 @@ export default class Editor extends React.Component<EditorProps, EditorState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const removeSrc = () => {
|
const removeSrc = () => {
|
||||||
|
this.pushUndoStack();
|
||||||
srcParent.children = srcParent.children.filter((e) => e.id != srcData.id);
|
srcParent.children = srcParent.children.filter((e) => e.id != srcData.id);
|
||||||
};
|
};
|
||||||
console.log("dstNode", dstNode);
|
console.log("dstNode", dstNode);
|
||||||
@@ -286,6 +290,7 @@ export default class Editor extends React.Component<EditorProps, EditorState> {
|
|||||||
message.warn("未选中节点");
|
message.warn("未选中节点");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this.pushUndoStack();
|
||||||
const curNodeData = this.graph.findDataById(curNodeId);
|
const curNodeData = this.graph.findDataById(curNodeId);
|
||||||
const newNodeData: BehaviorNodeModel = {
|
const newNodeData: BehaviorNodeModel = {
|
||||||
id: this.autoId++,
|
id: this.autoId++,
|
||||||
@@ -311,15 +316,17 @@ export default class Editor extends React.Component<EditorProps, EditorState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.onSelectNode(null);
|
this.onSelectNode(null);
|
||||||
|
this.pushUndoStack();
|
||||||
const rootData = this.graph.findDataById("1");
|
const rootData = this.graph.findDataById("1");
|
||||||
const parentData = Utils.findParent(rootData, curNodeId);
|
const parentData = Utils.findParent(rootData, curNodeId);
|
||||||
parentData.children = parentData.children.filter((e) => e.id != curNodeId);
|
parentData.children = parentData.children.filter((e) => e.id != curNodeId);
|
||||||
this.changeWithoutAnim();
|
this.changeWithoutAnim();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateNode(id: string) {
|
pushUndoStack() {
|
||||||
this.graph.changeData();
|
this.undoStack.push(Utils.cloneNodeData(this.graph.findDataById('1') as GraphNodeModel));
|
||||||
this.graph.layout();
|
console.log("push", this.undoStack);
|
||||||
|
this.redoStack = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
changeWithoutAnim() {
|
changeWithoutAnim() {
|
||||||
@@ -366,6 +373,7 @@ export default class Editor extends React.Component<EditorProps, EditorState> {
|
|||||||
if (!str || str == "") {
|
if (!str || str == "") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this.pushUndoStack();
|
||||||
const data = Utils.createTreeData(JSON.parse(str), this.state.settings);
|
const data = Utils.createTreeData(JSON.parse(str), this.state.settings);
|
||||||
this.autoId = Utils.refreshNodeId(data, this.autoId);
|
this.autoId = Utils.refreshNodeId(data, this.autoId);
|
||||||
this.onSelectNode(null);
|
this.onSelectNode(null);
|
||||||
@@ -381,6 +389,30 @@ export default class Editor extends React.Component<EditorProps, EditorState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
undo() {
|
||||||
|
if (this.undoStack.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const data = this.undoStack.pop();
|
||||||
|
this.graph.set("animate", false);
|
||||||
|
this.graph.changeData(Utils.createTreeData(data, this.state.settings));
|
||||||
|
this.graph.layout();
|
||||||
|
this.graph.set("animate", true);
|
||||||
|
this.redoStack.push(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
redo() {
|
||||||
|
if (this.redoStack.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const data = this.redoStack.pop();
|
||||||
|
this.graph.set("animate", false);
|
||||||
|
this.graph.changeData(Utils.createTreeData(data, this.state.settings));
|
||||||
|
this.graph.layout();
|
||||||
|
this.graph.set("animate", true);
|
||||||
|
this.undoStack.push(data);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { curNodeId, treeModel, settings } = this.state;
|
const { curNodeId, treeModel, settings } = this.state;
|
||||||
var curNode: any;
|
var curNode: any;
|
||||||
@@ -399,6 +431,7 @@ export default class Editor extends React.Component<EditorProps, EditorState> {
|
|||||||
settings={settings}
|
settings={settings}
|
||||||
updateNode={(id, forceUpdate) => {
|
updateNode={(id, forceUpdate) => {
|
||||||
if (forceUpdate) {
|
if (forceUpdate) {
|
||||||
|
this.pushUndoStack();
|
||||||
const data: any = this.graph.findDataById(id);
|
const data: any = this.graph.findDataById(id);
|
||||||
data.conf = settings.getNodeConf(data.name);
|
data.conf = settings.getNodeConf(data.name);
|
||||||
data.size = Utils.calcTreeNodeSize(data);
|
data.size = Utils.calcTreeNodeSize(data);
|
||||||
|
|||||||
@@ -62,6 +62,16 @@ export default class TreeTabs extends Component<TreeTabsProps, TreeTabsState> {
|
|||||||
}
|
}
|
||||||
message.success("已保存所有行为树");
|
message.success("已保存所有行为树");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ipcRenderer.on(MainEventType.UNDO, () => {
|
||||||
|
const editor = this.getCurEditor();
|
||||||
|
editor?.undo();
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcRenderer.on(MainEventType.REDO, () => {
|
||||||
|
const editor = this.getCurEditor();
|
||||||
|
editor?.redo();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getOpenTreesModel() {
|
getOpenTreesModel() {
|
||||||
|
|||||||
Reference in new issue
Block a user