From d0690f0398119fc0e8749676cba28c45dcc469f8 Mon Sep 17 00:00:00 2001 From: zhandouxiaojiji Date: Thu, 15 Oct 2020 13:24:25 +0800 Subject: [PATCH] add Properties --- common/BehaviorTreeModel.ts | 19 +++++++ index.html | 2 +- main-process/AppMenu.ts | 16 +++--- main-process/Settings.ts | 26 ++++----- main-process/main.tsx | 10 +++- render-process/Editor/Editor.css | 20 +++++++ render-process/Editor/Properties.tsx | 44 +++++++++++++++ render-process/Editor/index.tsx | 80 +++++++++++++++++++++++----- 8 files changed, 181 insertions(+), 36 deletions(-) create mode 100644 common/BehaviorTreeModel.ts create mode 100644 render-process/Editor/Editor.css create mode 100644 render-process/Editor/Properties.tsx diff --git a/common/BehaviorTreeModel.ts b/common/BehaviorTreeModel.ts new file mode 100644 index 0000000..9ca08c0 --- /dev/null +++ b/common/BehaviorTreeModel.ts @@ -0,0 +1,19 @@ +export interface BehaviorNodeTypeModel { + name: string; + type?: string; + desc?: string; + args?: string[][3]; + input?: string[]; + output?: string; + doc?: string; +} + +export interface BehaviorNodeModel { + id: number; + name: string; + desc?: string; +} + +export interface BehaviorTreeModel { + name: string; +} \ No newline at end of file diff --git a/index.html b/index.html index cffbde8..ebb1968 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,7 @@ - demo + 行为树编辑器 diff --git a/main-process/AppMenu.ts b/main-process/AppMenu.ts index ae7ee79..83e78b2 100644 --- a/main-process/AppMenu.ts +++ b/main-process/AppMenu.ts @@ -167,16 +167,16 @@ export default class AppMenu { } private createNodeMenu() { - const typeItems: MenuItemConstructorOptions[] = []; + const classifyItems: MenuItemConstructorOptions[] = []; const map: { [key: string]: MenuItemConstructorOptions } = {} - for (let t of this.settings.nodeTypes) { + for (let t of this.settings.nodeClassify) { let item: MenuItemConstructorOptions = { - id: t.type, - label: `${t.type}(${t.desc})`, + id: t.classify, + label: `${t.classify}(${t.desc})`, submenu: [], }; - typeItems.push(item); - map[t.type] = item; + classifyItems.push(item); + map[t.classify] = item; } const other: MenuItemConstructorOptions = { id: 'other', @@ -205,12 +205,12 @@ export default class AppMenu { } if(hasOther) { - typeItems.push(other); + classifyItems.push(other); } return new MenuItem({ label: "新建节点", - submenu: typeItems + submenu: classifyItems }); } } \ No newline at end of file diff --git a/main-process/Settings.ts b/main-process/Settings.ts index b370f52..74edbc0 100644 --- a/main-process/Settings.ts +++ b/main-process/Settings.ts @@ -1,7 +1,8 @@ import * as fs from 'fs'; +import { BehaviorNodeTypeModel } from '../common/BehaviorTreeModel'; -export interface BehaviorNodeType { - type: string; +export interface BehaviorNodeClassify { + classify: string; desc?: string; } @@ -9,16 +10,16 @@ export interface SettingsModel { recentWorkspaces?: string[]; recentFiles?: string[]; nodeConfigPath?: string; // 节点配置路径 - nodeTypes?: BehaviorNodeType[]; + nodeClassify?: BehaviorNodeClassify[]; } const settingPath = 'settings.json'; const sampleNodeConfig = 'sample-node-config.json'; -const sampleNodeTypes: BehaviorNodeType[] = [ - { type: "Composite", desc: "复合节点" }, - { type: "Decorator", desc: "修饰节点" }, - { type: "Condition", desc: "条件节点" }, - { type: "Action", desc: "行为节点" }, +const sampleNodeClassify: BehaviorNodeClassify[] = [ + { classify: "Composite", desc: "复合节点" }, + { classify: "Decorator", desc: "修饰节点" }, + { classify: "Condition", desc: "条件节点" }, + { classify: "Action", desc: "行为节点" }, ] export default class Settings { @@ -32,7 +33,7 @@ export default class Settings { recentWorkspaces: [], recentFiles: [], nodeConfigPath: sampleNodeConfig, - nodeTypes: sampleNodeTypes, + nodeClassify: sampleNodeClassify, }; this.save(); } @@ -49,10 +50,11 @@ export default class Settings { } get nodeConfig() { const str = fs.readFileSync(this.nodeConfigPath, 'utf8'); - return JSON.parse(str); + const types: BehaviorNodeTypeModel[] = JSON.parse(str); + return types; } - get nodeTypes() { - return this.settings.nodeTypes; + get nodeClassify() { + return this.settings.nodeClassify; } set(config: SettingsModel) { diff --git a/main-process/main.tsx b/main-process/main.tsx index 7c24c6d..56a285c 100644 --- a/main-process/main.tsx +++ b/main-process/main.tsx @@ -1,13 +1,14 @@ import { app, BrowserWindow, Menu, MenuItem, dialog, nativeTheme } from 'electron'; import AppMenu from './AppMenu' import Settings from './Settings'; +import MainEventType from '../common/MainEventType'; export class MainProcess { mainWindow: BrowserWindow; appMenu: AppMenu; settings: Settings; constructor() { - nativeTheme.themeSource = 'dark'; + nativeTheme.themeSource = 'dark'; app.on('ready', () => { this.createWindow(); }) @@ -23,7 +24,7 @@ export class MainProcess { }); } - createWindow (){ + createWindow() { this.settings = new Settings(); this.mainWindow = new BrowserWindow({ width: 1280, @@ -41,6 +42,11 @@ export class MainProcess { }); this.appMenu = new AppMenu(this); this.rebuildMenu(); + + const lastWorkspace = this.settings.recentWorkspaces[0]; + if(lastWorkspace) { + this.mainWindow.webContents.send(MainEventType.OPEN_WORKSPACE, lastWorkspace); + } } rebuildMenu() { diff --git a/render-process/Editor/Editor.css b/render-process/Editor/Editor.css new file mode 100644 index 0000000..523d59c --- /dev/null +++ b/render-process/Editor/Editor.css @@ -0,0 +1,20 @@ +.body { + width : 100%; + height : 100%; + position: fixed; +} + +.sider { + height : 100%; + overflow: hidden; +} + +.sider:hover { + overflow-y : auto; +} + +.content { + width : 100%; + height : 100%; + display: flex; +} \ No newline at end of file diff --git a/render-process/Editor/Properties.tsx b/render-process/Editor/Properties.tsx new file mode 100644 index 0000000..7460d12 --- /dev/null +++ b/render-process/Editor/Properties.tsx @@ -0,0 +1,44 @@ +import React, { Component } from "react"; +import { Menu, Input } from "antd"; +import * as fs from 'fs'; +import { BehaviorTreeModel } from "../../common/BehaviorTreeModel"; + +const { Search } = Input; + +export interface PropertiesProps { + workspace: string; + onOpenTree: (path: string) => void; + trees: BehaviorTreeModel[]; +} + +interface PropertiesState { + +} + +export default class Properties extends Component { + state: PropertiesState = { + + }; + + componentDidMount() { + + } + + render() { + return ( +
+ { + + }} + /> + + test + +
+ ) + } +} \ No newline at end of file diff --git a/render-process/Editor/index.tsx b/render-process/Editor/index.tsx index 0333761..18be383 100644 --- a/render-process/Editor/index.tsx +++ b/render-process/Editor/index.tsx @@ -1,18 +1,26 @@ import React, { Component } from "react"; -import { DatePicker } from 'antd'; +import { Layout } from 'antd'; import { ipcRenderer } from 'electron'; +import * as path from 'path'; import * as fs from 'fs'; import MainEventType from "../../common/MainEventType"; +import Properties from "./Properties"; +import './Editor.css'; +import { BehaviorTreeModel } from "../../common/BehaviorTreeModel"; + +const { Header, Sider, Content, Footer } = Layout; interface EditorState { workspace: string; filepaths: string[]; + trees: BehaviorTreeModel[]; } export default class Editor extends Component { state: EditorState = { workspace: '', filepaths: [], + trees: [], } componentDidMount() { @@ -20,17 +28,51 @@ export default class Editor extends Component { console.log("on open file", path); const filepaths = this.state.filepaths; filepaths.push(path); - this.setState({filepaths}); + this.setState({ filepaths }); }); ipcRenderer.on(MainEventType.OPEN_WORKSPACE, (event: any, workspace: any) => { console.log("on open workspace", workspace); - this.setState({workspace}); + this.setState({ workspace }); + this.loadAllTrees(); }); + + this.loadAllTrees(); + } + + loadAllTrees() { + const workspace = this.state.workspace + if(workspace == '' || !fs.existsSync(workspace)) { + console.log("workspace not exist", workspace); + return; + } + + const files = fs.readdirSync(workspace); + const list = [] + files.forEach((filename) => { + console.log("load path", filename); + const stat = fs.statSync(path.join(workspace, filename)) + if (stat.isFile()) { + let tree = this.loadTree(filename.slice(0, -5)); + list.push(tree); + console.log("loaded", filename); + } + }) + } + + loadTree(name: string) { + const filename = this.state.workspace + '/' + name + '.json'; + if (!fs.existsSync(filename)) { + return; + } + const str = fs.readFileSync(filename, 'utf8'); + let tree: BehaviorTreeModel = JSON.parse(str); + tree.name = name; + return tree; } renderJson() { - if(this.state.filepaths.length>0) { + if (this.state.filepaths.length > 0) { const path = this.state.filepaths[0]; const str = fs.readFileSync(path, 'utf8'); return (
{str}
) @@ -38,16 +80,28 @@ export default class Editor extends Component { } render() { + const { trees } = this.state; return ( -
-
- 当前目录:{this.state.workspace} -
-
- 当前文件:{this.state.filepaths.join("\n")} -
- {this.renderJson()} -
+ + + { + console.log("open tree", path); + }} + trees={trees} + /> + + +
+ 当前目录:{this.state.workspace} +
+
+ 当前文件:{this.state.filepaths.join("\n")} +
+ {this.renderJson()} +
+
) } }; \ No newline at end of file