style: format codes

This commit is contained in:
duanhongbo committed 2020-11-12 17:24:08 +08:00
1 parent c3ea18e307
commit 00e79d641e
14 files changed
+408 -442

No files matched your search

+5 -5
View File
@@ -1,9 +1,9 @@
import { TreeGraphData } from "@antv/g6/lib/types"; import { TreeGraphData } from "@antv/g6/lib/types";
export interface ArgsDefType { export interface ArgsDefType {
name: string, name: string;
type: string, type: string;
desc: string, desc: string;
} }
export interface BehaviorNodeTypeModel { export interface BehaviorNodeTypeModel {
name: string; name: string;
@@ -19,7 +19,7 @@ export interface BehaviorNodeModel {
id: number; id: number;
name: string; name: string;
desc?: string; desc?: string;
args?: {[key: string]: any}; args?: { [key: string]: any };
input?: string[]; input?: string[];
output?: string[]; output?: string[];
children?: BehaviorNodeModel[]; children?: BehaviorNodeModel[];
@@ -34,7 +34,7 @@ export interface BehaviorTreeModel {
export interface GraphNodeModel extends TreeGraphData { export interface GraphNodeModel extends TreeGraphData {
name: string; name: string;
desc?: string; desc?: string;
args?: {[key: string]: any}; args?: { [key: string]: any };
input?: string[]; input?: string[];
output?: string[]; output?: string[];
children?: GraphNodeModel[]; children?: GraphNodeModel[];
+8 -8
View File
@@ -2,11 +2,11 @@ export default {
OPEN_FILE: "OPEN_FILE", OPEN_FILE: "OPEN_FILE",
OPEN_DIR: "OPEN_DIR", OPEN_DIR: "OPEN_DIR",
OPEN_WORKSPACE: "OPEN_WORKSPACE", OPEN_WORKSPACE: "OPEN_WORKSPACE",
CREATE_TREE: 'CREATE_TREE', CREATE_TREE: "CREATE_TREE",
CREATE_NODE: 'CREATE_NODE', CREATE_NODE: "CREATE_NODE",
DELETE_NODE: 'DELETE_NODE', DELETE_NODE: "DELETE_NODE",
COPY_NODE: 'COPY_NODE', COPY_NODE: "COPY_NODE",
PASTE_NODE: 'PASTE_NODE', PASTE_NODE: "PASTE_NODE",
SAVE: 'SAVE', SAVE: "SAVE",
SAVE_ALL: 'SAVE_ALL', SAVE_ALL: "SAVE_ALL",
} };
+26 -27
View File
@@ -1,17 +1,17 @@
import { TreeGraphData } from "@antv/g6/lib/types" import { TreeGraphData } from "@antv/g6/lib/types";
import { BehaviorNodeModel, BehaviorTreeModel, GraphNodeModel } from "./BehaviorTreeModel"; import { BehaviorNodeModel, BehaviorTreeModel, GraphNodeModel } from "./BehaviorTreeModel";
import Settings from "../main-process/Settings"; import Settings from "../main-process/Settings";
import { remote } from "electron"; import { remote } from "electron";
import * as path from 'path'; import * as path from "path";
export const cloneNodeData = (nodeData: GraphNodeModel) => { export const cloneNodeData = (nodeData: GraphNodeModel) => {
const newData: GraphNodeModel = { const newData: GraphNodeModel = {
id: nodeData.id + "new", id: nodeData.id + "new",
name: nodeData.name, name: nodeData.name,
conf: nodeData.conf, conf: nodeData.conf,
} };
return newData; return newData;
} };
export const refreshNodeId = (nodeData: GraphNodeModel, id?: number) => { export const refreshNodeId = (nodeData: GraphNodeModel, id?: number) => {
if (!id) { if (!id) {
@@ -19,12 +19,12 @@ export const refreshNodeId = (nodeData: GraphNodeModel, id?: number) => {
} }
nodeData.id = (id++).toString(); nodeData.id = (id++).toString();
if (nodeData.children) { if (nodeData.children) {
nodeData.children.forEach(child => { nodeData.children.forEach((child) => {
id = refreshNodeId(child, id); id = refreshNodeId(child, id);
}) });
} }
return id; return id;
} };
export const calcTreeNodeSize = (treeNode: GraphNodeModel) => { export const calcTreeNodeSize = (treeNode: GraphNodeModel) => {
var height = 40; var height = 40;
@@ -32,12 +32,12 @@ export const calcTreeNodeSize = (treeNode: GraphNodeModel) => {
if (Array.isArray(obj) || (obj && Object.keys(obj).length > 0)) { if (Array.isArray(obj) || (obj && Object.keys(obj).length > 0)) {
height += 25; height += 25;
} }
} };
updateHeight(treeNode.conf.args); updateHeight(treeNode.conf.args);
updateHeight(treeNode.conf.input); updateHeight(treeNode.conf.input);
updateHeight(treeNode.conf.output); updateHeight(treeNode.conf.output);
return [200, height]; return [200, height];
} };
export const createTreeData = (bNode: BehaviorNodeModel, settings: Settings) => { export const createTreeData = (bNode: BehaviorNodeModel, settings: Settings) => {
const treeData: GraphNodeModel = { const treeData: GraphNodeModel = {
@@ -48,17 +48,17 @@ export const createTreeData = (bNode: BehaviorNodeModel, settings: Settings) =>
input: bNode.input, input: bNode.input,
output: bNode.output, output: bNode.output,
conf: settings.getNodeConf(bNode.name), conf: settings.getNodeConf(bNode.name),
} };
treeData.size = calcTreeNodeSize(treeData); treeData.size = calcTreeNodeSize(treeData);
if (bNode.children) { if (bNode.children) {
treeData.children = []; treeData.children = [];
bNode.children.forEach(child => { bNode.children.forEach((child) => {
treeData.children.push(createTreeData(child, settings)); treeData.children.push(createTreeData(child, settings));
}) });
} }
calcTreeNodeSize(treeData); calcTreeNodeSize(treeData);
return treeData; return treeData;
} };
export const createFileData = (gNode: GraphNodeModel) => { export const createFileData = (gNode: GraphNodeModel) => {
const nodeData: BehaviorNodeModel = { const nodeData: BehaviorNodeModel = {
@@ -68,15 +68,15 @@ export const createFileData = (gNode: GraphNodeModel) => {
args: gNode.args || undefined, args: gNode.args || undefined,
input: gNode.input || undefined, input: gNode.input || undefined,
output: gNode.output || undefined, output: gNode.output || undefined,
} };
if (gNode.children) { if (gNode.children) {
nodeData.children = []; nodeData.children = [];
gNode.children.forEach(child => { gNode.children.forEach((child) => {
nodeData.children.push(createFileData(child)); nodeData.children.push(createFileData(child));
}) });
} }
return nodeData; return nodeData;
} };
export const findParent = (node: TreeGraphData, id: string): TreeGraphData | null => { export const findParent = (node: TreeGraphData, id: string): TreeGraphData | null => {
if (node.children) { if (node.children) {
@@ -89,11 +89,10 @@ export const findParent = (node: TreeGraphData, id: string): TreeGraphData | nul
return parent; return parent;
} }
} }
} }
} }
return null; return null;
} };
export const findFromAllChildren = (node: TreeGraphData, id: string): TreeGraphData | null => { export const findFromAllChildren = (node: TreeGraphData, id: string): TreeGraphData | null => {
if (node.id == id) { if (node.id == id) {
@@ -108,24 +107,24 @@ export const findFromAllChildren = (node: TreeGraphData, id: string): TreeGraphD
} }
} }
return null; return null;
} };
export const getRemoteSettings = () => { export const getRemoteSettings = () => {
return remote.getGlobal("settings") as Settings; return remote.getGlobal("settings") as Settings;
} };
export const fileName2treeName = (filename: string) => { export const fileName2treeName = (filename: string) => {
return path.basename(filename).slice(0, -5); return path.basename(filename).slice(0, -5);
} };
export const createNewTree = (filename: string) => { export const createNewTree = (filename: string) => {
const tree: BehaviorTreeModel = { const tree: BehaviorTreeModel = {
name: fileName2treeName(filename), name: fileName2treeName(filename),
root: { root: {
id: 1, id: 1,
name: 'Sequence', name: "Sequence",
desc: '新建行为树' desc: "新建行为树",
} },
} };
return tree; return tree;
} };
+6 -6
View File
@@ -121,13 +121,13 @@ export default class AppMenu {
}); });
if (res.filePath) { if (res.filePath) {
const curWorkspace = this.settings.curWorkspace; const curWorkspace = this.settings.curWorkspace;
curWorkspace.writeAllTrees(res.filePath,(err)=>{ curWorkspace.writeAllTrees(res.filePath, (err) => {
const msg = err?err:"导出成功"; const msg = err ? err : "导出成功";
dialog.showMessageBox({ dialog.showMessageBox({
type:"info", type: "info",
buttons:["ok"], buttons: ["ok"],
message:msg message: msg,
}) });
}); });
} }
})(); })();
+21 -23
View File
@@ -1,13 +1,13 @@
import { app, BrowserWindow, Menu, MenuItem, dialog, nativeTheme } from 'electron'; import { app, BrowserWindow, Menu, MenuItem, dialog, nativeTheme } from "electron";
import AppMenu from './AppMenu' import AppMenu from "./AppMenu";
import Settings from './Settings'; import Settings from "./Settings";
import MainEventType from '../common/MainEventType'; import MainEventType from "../common/MainEventType";
const electronLocalshortcut = require('electron-localshortcut'); const electronLocalshortcut = require("electron-localshortcut");
// 一些暴露给render-process的全局变量 // 一些暴露给render-process的全局变量
export interface Global { export interface Global {
settings: Settings settings: Settings;
} }
declare var global: Global; declare var global: Global;
@@ -16,24 +16,24 @@ export class MainProcess {
appMenu: AppMenu; appMenu: AppMenu;
settings: Settings; settings: Settings;
constructor() { constructor() {
nativeTheme.themeSource = 'dark'; nativeTheme.themeSource = "dark";
app.on('ready', () => { app.on("ready", () => {
this.createWindow(); this.createWindow();
electronLocalshortcut.register(this.mainWindow, 'Ctrl+C', () => { electronLocalshortcut.register(this.mainWindow, "Ctrl+C", () => {
this.mainWindow.webContents.send(MainEventType.COPY_NODE); this.mainWindow.webContents.send(MainEventType.COPY_NODE);
}); });
electronLocalshortcut.register(this.mainWindow, 'Ctrl+V', () => { electronLocalshortcut.register(this.mainWindow, "Ctrl+V", () => {
this.mainWindow.webContents.send(MainEventType.PASTE_NODE); this.mainWindow.webContents.send(MainEventType.PASTE_NODE);
}); });
}) });
app.on('window-all-closed', () => { app.on("window-all-closed", () => {
if (process.platform !== 'darwin') { if (process.platform !== "darwin") {
app.quit() app.quit();
} }
}) });
app.on('activate', () => { app.on("activate", () => {
if (this.mainWindow === null) { if (this.mainWindow === null) {
this.createWindow() this.createWindow();
} }
}); });
} }
@@ -48,15 +48,15 @@ export class MainProcess {
webPreferences: { webPreferences: {
nodeIntegration: true, nodeIntegration: true,
enableRemoteModule: true, enableRemoteModule: true,
} },
// fullscreenable:false, // fullscreenable:false,
// maximizable:false // maximizable:false
}); });
this.mainWindow.maximize(); this.mainWindow.maximize();
// mainWindow.webContents.openDevTools(); // mainWindow.webContents.openDevTools();
this.mainWindow.loadFile('index.html'); this.mainWindow.loadFile("index.html");
this.mainWindow.on('closed', function () { this.mainWindow.on("closed", function () {
this.mainWindow = null this.mainWindow = null;
}); });
this.appMenu = new AppMenu(this); this.appMenu = new AppMenu(this);
this.rebuildMenu(); this.rebuildMenu();
@@ -67,6 +67,4 @@ export class MainProcess {
} }
} }
export default new MainProcess(); export default new MainProcess();
+8 -9
View File
@@ -1,6 +1,6 @@
import * as fs from 'fs'; import * as fs from "fs";
import { BehaviorNodeTypeModel } from '../common/BehaviorTreeModel'; import { BehaviorNodeTypeModel } from "../common/BehaviorTreeModel";
import Workspace from './Workspace'; import Workspace from "./Workspace";
export interface BehaviorNodeClassify { export interface BehaviorNodeClassify {
classify: string; classify: string;
@@ -13,14 +13,13 @@ export interface SettingsModel {
nodeClassify?: BehaviorNodeClassify[]; nodeClassify?: BehaviorNodeClassify[];
} }
const settingPath = 'settings.json'; const settingPath = "settings.json";
const sampleNodeClassify: BehaviorNodeClassify[] = [ const sampleNodeClassify: BehaviorNodeClassify[] = [
{ classify: "Composite", desc: "复合节点" }, { classify: "Composite", desc: "复合节点" },
{ classify: "Decorator", desc: "修饰节点" }, { classify: "Decorator", desc: "修饰节点" },
{ classify: "Condition", desc: "条件节点" }, { classify: "Condition", desc: "条件节点" },
{ classify: "Action", desc: "行为节点" }, { classify: "Action", desc: "行为节点" },
] ];
export default class Settings { export default class Settings {
private settings: SettingsModel; private settings: SettingsModel;
@@ -49,18 +48,18 @@ export default class Settings {
set(config: SettingsModel) { set(config: SettingsModel) {
this.settings = { this.settings = {
...this.settings, ...this.settings,
...config ...config,
}; };
this.save(); this.save();
} }
load() { load() {
if (fs.existsSync(settingPath)) { if (fs.existsSync(settingPath)) {
const str = fs.readFileSync(settingPath, 'utf8'); const str = fs.readFileSync(settingPath, "utf8");
this.settings = JSON.parse(str); this.settings = JSON.parse(str);
} else { } else {
this.settings = { this.settings = {
recentWorkspaces: ['sample/workspace.json'], recentWorkspaces: ["sample/workspace.json"],
recentFiles: [], recentFiles: [],
nodeClassify: sampleNodeClassify, nodeClassify: sampleNodeClassify,
}; };
+8 -6
View File
@@ -32,12 +32,12 @@ export default class Workspace {
return; return;
} }
try { try {
const str = fs.readFileSync(this.filepath, 'utf8'); const str = fs.readFileSync(this.filepath, "utf8");
const model = JSON.parse(str) as WorkspaceModel; const model = JSON.parse(str) as WorkspaceModel;
if (model.isRelative) { if (model.isRelative) {
const root = path.dirname(this.filepath); const root = path.dirname(this.filepath);
this.nodeConfPath = root + '/' + model.nodeConfPath; this.nodeConfPath = root + "/" + model.nodeConfPath;
this.workdir = root + '/' + model.workdir; this.workdir = root + "/" + model.workdir;
} else { } else {
this.nodeConfPath = model.nodeConfPath; this.nodeConfPath = model.nodeConfPath;
this.workdir = model.workdir; this.workdir = model.workdir;
@@ -54,11 +54,13 @@ export default class Workspace {
return; return;
} }
const types: BehaviorNodeTypeModel[] = JSON.parse(fs.readFileSync(this.nodeConfPath, 'utf8')); const types: BehaviorNodeTypeModel[] = JSON.parse(
fs.readFileSync(this.nodeConfPath, "utf8")
);
this.name2conf = {}; this.name2conf = {};
types.forEach(t => { types.forEach((t) => {
this.name2conf[t.name] = t; this.name2conf[t.name] = t;
}) });
this.types = types; this.types = types;
} }
+88 -94
View File
@@ -1,22 +1,35 @@
import React from 'react'; import React from "react";
import { Card, Divider, Form, Input, AutoComplete, Select, Switch, InputNumber, notification, message } from 'antd'; import {
import { INode } from '@antv/g6/lib/interface/item'; Card,
import { BehaviorNodeModel, BehaviorNodeTypeModel, ArgsDefType } from '../../common/BehaviorTreeModel'; Divider,
import Settings from '../../main-process/Settings'; Form,
import { FormInstance } from 'antd/lib/form'; Input,
import Markdown from 'react-markdown'; AutoComplete,
Select,
Switch,
InputNumber,
notification,
message,
} from "antd";
import { INode } from "@antv/g6/lib/interface/item";
import {
BehaviorNodeModel,
BehaviorNodeTypeModel,
ArgsDefType,
} from "../../common/BehaviorTreeModel";
import Settings from "../../main-process/Settings";
import { FormInstance } from "antd/lib/form";
import Markdown from "react-markdown";
const { Item } = Form; const { Item } = Form;
interface NodePanelProps { interface NodePanelProps {
model: BehaviorNodeModel; model: BehaviorNodeModel;
settings: Settings; settings: Settings;
updateNode: (id: string, forceUpdate:boolean) => void; updateNode: (id: string, forceUpdate: boolean) => void;
} }
interface NodePanelState { interface NodePanelState {}
}
export default class NodePanel extends React.Component<NodePanelProps> { export default class NodePanel extends React.Component<NodePanelProps> {
formRef = React.createRef<FormInstance>(); formRef = React.createRef<FormInstance>();
@@ -32,7 +45,7 @@ export default class NodePanel extends React.Component<NodePanelProps> {
name: model.name, name: model.name,
desc: model.desc, desc: model.desc,
debug: model.debug, debug: model.debug,
customArgs: model.args ? JSON.stringify(model.args, null, " ") : '', customArgs: model.args ? JSON.stringify(model.args, null, " ") : "",
}; };
if (model.args) { if (model.args) {
for (let k in model.args) { for (let k in model.args) {
@@ -42,20 +55,20 @@ export default class NodePanel extends React.Component<NodePanelProps> {
if (model.input) { if (model.input) {
model.input.forEach((v, i) => { model.input.forEach((v, i) => {
initialValues[`input.${i}`] = v; initialValues[`input.${i}`] = v;
}) });
} }
if (model.output) { if (model.output) {
model.output.forEach((v, i) => { model.output.forEach((v, i) => {
initialValues[`output.${i}`] = v; initialValues[`output.${i}`] = v;
}) });
} }
return initialValues; return initialValues;
} }
onFinish = (values: any) => { onFinish = (values: any) => {
console.log('Success:', values); console.log("Success:", values);
const { updateNode, model, settings } = this.props; const { updateNode, model, settings } = this.props;
const conf = settings.getNodeConf(values.name) const conf = settings.getNodeConf(values.name);
if (!conf) { if (!conf) {
notification.warn({ message: `节点${values.name}未定义` }); notification.warn({ message: `节点${values.name}未定义` });
return; return;
@@ -78,24 +91,26 @@ export default class NodePanel extends React.Component<NodePanelProps> {
} }
if (conf.args) { if (conf.args) {
conf.args.forEach(e => { conf.args.forEach((e) => {
const k = 'args.' + e.name; const k = "args." + e.name;
if (e.type.indexOf('number') > 0) { if (e.type.indexOf("number") > 0) {
args[e.name] = Number(values[k]); args[e.name] = Number(values[k]);
} else { } else {
args[e.name] = values[k]; args[e.name] = values[k];
} }
}) });
} }
model.args = args; model.args = args;
this.formRef.current.setFieldsValue({ customArgs: model.args ? JSON.stringify(model.args, null, " ") : '' }); this.formRef.current.setFieldsValue({
customArgs: model.args ? JSON.stringify(model.args, null, " ") : "",
});
if (conf.input) { if (conf.input) {
model.input = []; model.input = [];
conf.input.forEach((e, i) => { conf.input.forEach((e, i) => {
model.input.push(values['input.' + i] || ''); model.input.push(values["input." + i] || "");
}) });
} else { } else {
model.input = null; model.input = null;
} }
@@ -103,8 +118,8 @@ export default class NodePanel extends React.Component<NodePanelProps> {
if (conf.output) { if (conf.output) {
model.output = []; model.output = [];
conf.output.forEach((e, i) => { conf.output.forEach((e, i) => {
model.output.push(values['output.' + i] || ''); model.output.push(values["output." + i] || "");
}) });
} else { } else {
model.output = null; model.output = null;
} }
@@ -116,13 +131,13 @@ export default class NodePanel extends React.Component<NodePanelProps> {
}; };
onFinishFailed = (errorInfo: any) => { onFinishFailed = (errorInfo: any) => {
console.log('Failed:', errorInfo); console.log("Failed:", errorInfo);
}; };
handleSubmit = () => { handleSubmit = () => {
console.log("handleSubmit"); console.log("handleSubmit");
this.formRef.current.submit(); this.formRef.current.submit();
} };
render() { render() {
const { model, settings } = this.props; const { model, settings } = this.props;
@@ -132,14 +147,14 @@ export default class NodePanel extends React.Component<NodePanelProps> {
const options: any = []; const options: any = [];
settings.nodeConfig.map((e) => { settings.nodeConfig.map((e) => {
options.push({ label: `${e.name}(${e.desc})`, value: e.name }); options.push({ label: `${e.name}(${e.desc})`, value: e.name });
}) });
const layout = { const layout = {
labelCol: { span: 6 }, labelCol: { span: 6 },
wrapperCol: { span: 18 }, wrapperCol: { span: 18 },
}; };
return ( return (
<Card title={title} style={{ height: window.screen.height - 100, overflow: 'auto' }}> <Card title={title} style={{ height: window.screen.height - 100, overflow: "auto" }}>
<Form <Form
{...layout} {...layout}
name="basic" name="basic"
@@ -147,34 +162,25 @@ export default class NodePanel extends React.Component<NodePanelProps> {
initialValues={this.getInitialValues()} initialValues={this.getInitialValues()}
ref={this.formRef} ref={this.formRef}
> >
<Item <Item label="节点id">
label="节点id"
>
<Input value={model.id} disabled={true} /> <Input value={model.id} disabled={true} />
</Item> </Item>
<Item <Item label="节点名称" name="name">
label="节点名称"
name="name"
>
<AutoComplete <AutoComplete
options={options} options={options}
onBlur={this.handleSubmit} onBlur={this.handleSubmit}
filterOption={(inputValue: string, option: any) => { filterOption={(inputValue: string, option: any) => {
return option.label.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1 return (
option.label.toUpperCase().indexOf(inputValue.toUpperCase()) !==
-1
);
}} }}
/> />
</Item> </Item>
<Item <Item label="节点说明" name="desc">
label="节点说明"
name="desc"
>
<Input onBlur={this.handleSubmit} /> <Input onBlur={this.handleSubmit} />
</Item> </Item>
<Item <Item label="调试开关" name="debug" valuePropName="checked">
label="调试开关"
name="debug"
valuePropName='checked'
>
<Switch onChange={this.handleSubmit} /> <Switch onChange={this.handleSubmit} />
</Item> </Item>
<Markdown source={conf.doc} /> <Markdown source={conf.doc} />
@@ -182,8 +188,8 @@ export default class NodePanel extends React.Component<NodePanelProps> {
{this.renderArgs(conf)} {this.renderArgs(conf)}
{this.renderOutputs(conf)} {this.renderOutputs(conf)}
</Form> </Form>
</Card > </Card>
) );
} }
renderArgs(conf: BehaviorNodeTypeModel) { renderArgs(conf: BehaviorNodeTypeModel) {
@@ -197,53 +203,51 @@ export default class NodePanel extends React.Component<NodePanelProps> {
if (e.type.indexOf("string") >= 0) { if (e.type.indexOf("string") >= 0) {
return <Input onBlur={this.handleSubmit} />; return <Input onBlur={this.handleSubmit} />;
} else if (e.type.indexOf("int") >= 0) { } else if (e.type.indexOf("int") >= 0) {
return <InputNumber style={{ width: '100%' }} onBlur={this.handleSubmit} />; return <InputNumber style={{ width: "100%" }} onBlur={this.handleSubmit} />;
} else if (e.type.indexOf("boolean") >= 0) { } else if (e.type.indexOf("boolean") >= 0) {
return <Switch onChange={this.handleSubmit} />; return <Switch onChange={this.handleSubmit} />;
} else if (e.type.indexOf("lua") >= 0) { } else if (e.type.indexOf("lua") >= 0) {
return <Input onBlur={this.handleSubmit} placeholder={'公式'} />; return <Input onBlur={this.handleSubmit} placeholder={"公式"} />;
}
} }
};
// 自定义参数 // 自定义参数
const customArgs = () => { const customArgs = () => {
return ( return (
<Item <Item name="customArgs" label="自定义" key="customArgs">
name='customArgs'
label='自定义'
key='customArgs'
>
<Input.TextArea onBlur={this.handleSubmit} style={{ minHeight: 100 }} /> <Input.TextArea onBlur={this.handleSubmit} style={{ minHeight: 100 }} />
</Item> </Item>
) );
};
}
return ( return (
<div> <div>
<Divider orientation="left"><h3>常量参数</h3></Divider> <Divider orientation="left">
{conf && conf.args && conf.args.map((e, i: number) => { <h3>常量参数</h3>
</Divider>
{conf &&
conf.args &&
conf.args.map((e, i: number) => {
const required = e.type.indexOf("?") == -1; const required = e.type.indexOf("?") == -1;
return ( return (
<Item <Item
name={`args.${e.name}`} name={`args.${e.name}`}
label={e.desc} label={e.desc}
key={`args.${e.name}`} key={`args.${e.name}`}
valuePropName={e.type.indexOf("boolean") >= 0 ? 'checked' : undefined} valuePropName={
rules={[ e.type.indexOf("boolean") >= 0 ? "checked" : undefined
{ required, message: `${e.desc}(${e.name})为必填字段` } }
]} rules={[{ required, message: `${e.desc}(${e.name})为必填字段` }]}
> >
{normalArgs(e)} {normalArgs(e)}
</Item> </Item>
) );
})} })}
{customArgs()} {customArgs()}
</div > </div>
); );
} }
renderInputs(conf: BehaviorNodeTypeModel) { renderInputs(conf: BehaviorNodeTypeModel) {
if (!conf.input || !conf.input || conf.input.length == 0) { if (!conf.input || !conf.input || conf.input.length == 0) {
return null; return null;
@@ -251,22 +255,18 @@ export default class NodePanel extends React.Component<NodePanelProps> {
return ( return (
<div> <div>
<Divider orientation="left"><h3>输入变量</h3></Divider> <Divider orientation="left">
{ <h3>输入变量</h3>
conf.input.map((e, i) => { </Divider>
{conf.input.map((e, i) => {
return ( return (
<Item <Item label={e} name={`input.${i}`} key={`input.${i}`}>
label={e}
name={`input.${i}`}
key={`input.${i}`}
>
<Input onBlur={this.handleSubmit} /> <Input onBlur={this.handleSubmit} />
</Item> </Item>
) );
}) })}
}
</div> </div>
) );
} }
renderOutputs(conf: BehaviorNodeTypeModel) { renderOutputs(conf: BehaviorNodeTypeModel) {
@@ -275,23 +275,17 @@ export default class NodePanel extends React.Component<NodePanelProps> {
} }
return ( return (
<div> <div>
<Divider orientation="left"><h3>输出变量</h3></Divider> <Divider orientation="left">
{ <h3>输出变量</h3>
conf.output.map((e, i) => { </Divider>
{conf.output.map((e, i) => {
return ( return (
<Item <Item label={e} name={`output.${i}`} key={`output.${i}`}>
label={e}
name={`output.${i}`}
key={`output.${i}`}
>
<Input onBlur={this.handleSubmit} /> <Input onBlur={this.handleSubmit} />
</Item> </Item>
) );
}) })}
}
</div> </div>
) );
} }
} }
+9 -14
View File
@@ -1,33 +1,28 @@
import React from 'react'; import React from "react";
import { Card } from 'antd'; import { Card } from "antd";
import { INode } from '@antv/g6/lib/interface/item'; import { INode } from "@antv/g6/lib/interface/item";
import { BehaviorTreeModel } from '../../common/BehaviorTreeModel'; import { BehaviorTreeModel } from "../../common/BehaviorTreeModel";
interface TreePanelProps { interface TreePanelProps {
model?: BehaviorTreeModel; model?: BehaviorTreeModel;
} }
interface TreePanelState { interface TreePanelState {}
}
export default class TreePanel extends React.Component<TreePanelProps, TreePanelState> { export default class TreePanel extends React.Component<TreePanelProps, TreePanelState> {
state: TreePanelState = {}; state: TreePanelState = {};
componentDidMount() { componentDidMount() {}
}
render() { render() {
const { model } = this.props; const { model } = this.props;
if(!model) { if (!model) {
return (<div/>) return <div />;
} }
return ( return (
<Card title="概况" style={{ height: "100%" }}> <Card title="概况" style={{ height: "100%" }}>
行为树:{model.name} 行为树:{model.name}
</Card> </Card>
) );
} }
} }
+101 -99
View File
@@ -1,17 +1,21 @@
import * as React from 'react'; import * as React from "react";
import * as fs from 'fs'; import * as fs from "fs";
import * as path from 'path'; import * as path from "path";
import { Row, Col, message } from 'antd'; import { Row, Col, message } from "antd";
import NodePanel from './NodePanel'; import NodePanel from "./NodePanel";
import G6, { TreeGraph } from '@antv/g6'; import G6, { TreeGraph } from "@antv/g6";
import { G6GraphEvent } from '@antv/g6/lib/interface/behavior'; import { G6GraphEvent } from "@antv/g6/lib/interface/behavior";
import * as Utils from '../../common/Utils'; import * as Utils from "../../common/Utils";
import { BehaviorTreeModel, GraphNodeModel, BehaviorNodeModel } from '../../common/BehaviorTreeModel'; import {
import TreePanel from './TreePanel'; BehaviorTreeModel,
import Settings from '../../main-process/Settings'; GraphNodeModel,
BehaviorNodeModel,
} from "../../common/BehaviorTreeModel";
import TreePanel from "./TreePanel";
import Settings from "../../main-process/Settings";
import './Editor.css'; import "./Editor.css";
import { clipboard } from 'electron'; import { clipboard } from "electron";
export interface EditorProps { export interface EditorProps {
filepath: string; filepath: string;
@@ -46,38 +50,40 @@ export default class Editor extends React.Component<EditorProps, EditorState> {
// fitCenter: true, // fitCenter: true,
modes: { modes: {
default: [ default: [
'drag-canvas', "drag-canvas",
'zoom-canvas', "zoom-canvas",
'click-select', "click-select",
'hover', "hover",
{ {
type: 'collapse-expand', type: "collapse-expand",
trigger: 'dblclick', trigger: "dblclick",
onChange: (item, collapsed) => { onChange: (item, collapsed) => {
this.onSelectNode(item.getID()); this.onSelectNode(item.getID());
const data = item.getModel(); const data = item.getModel();
data.collapsed = collapsed; data.collapsed = collapsed;
graph.setItemState(item, 'collapsed', data.collapsed as boolean); graph.setItemState(item, "collapsed", data.collapsed as boolean);
const icon = data.collapsed ? G6.Marker.expand : G6.Marker.collapse; const icon = data.collapsed ? G6.Marker.expand : G6.Marker.collapse;
const marker = item.get('group').find((ele: any) => ele.get('name') === 'collapse-icon'); const marker = item
marker.attr('symbol', icon); .get("group")
.find((ele: any) => ele.get("name") === "collapse-icon");
marker.attr("symbol", icon);
return true; return true;
}, },
}, },
] ],
}, },
defaultEdge: { defaultEdge: {
type: 'cubic-horizontal', type: "cubic-horizontal",
style: { style: {
stroke: '#A3B1BF' stroke: "#A3B1BF",
} },
}, },
defaultNode: { defaultNode: {
type: "TreeNode", type: "TreeNode",
}, },
layout: { layout: {
type: 'compactBox', type: "compactBox",
direction: 'LR', direction: "LR",
getHGap: () => 50, getHGap: () => 50,
getWidth: (d: GraphNodeModel) => { getWidth: (d: GraphNodeModel) => {
return 150; return 150;
@@ -88,27 +94,27 @@ export default class Editor extends React.Component<EditorProps, EditorState> {
} else { } else {
return 50; return 50;
} }
} },
} },
}); });
graph.on('node:mouseenter', (e: G6GraphEvent) => { graph.on("node:mouseenter", (e: G6GraphEvent) => {
const { item } = e; const { item } = e;
if (item.hasState('selected')) { if (item.hasState("selected")) {
return; return;
} }
graph.setItemState(item, 'hover', true); graph.setItemState(item, "hover", true);
}); });
graph.on('node:mouseleave', (e: G6GraphEvent) => { graph.on("node:mouseleave", (e: G6GraphEvent) => {
const { item } = e; const { item } = e;
if (item.hasState('selected')) { if (item.hasState("selected")) {
return; return;
} }
graph.setItemState(item, 'hover', false); graph.setItemState(item, "hover", false);
}); });
graph.on('nodeselectchange', (e: G6GraphEvent) => { graph.on("nodeselectchange", (e: G6GraphEvent) => {
if (e.target) { if (e.target) {
this.onSelectNode(e.target.getID()); this.onSelectNode(e.target.getID());
} else { } else {
@@ -118,69 +124,69 @@ export default class Editor extends React.Component<EditorProps, EditorState> {
const clearDragDstState = () => { const clearDragDstState = () => {
if (this.dragDstId) { if (this.dragDstId) {
graph.setItemState(this.dragDstId, 'dragRight', false); graph.setItemState(this.dragDstId, "dragRight", false);
graph.setItemState(this.dragDstId, 'dragDown', false); graph.setItemState(this.dragDstId, "dragDown", false);
graph.setItemState(this.dragDstId, 'dragUp', false); graph.setItemState(this.dragDstId, "dragUp", false);
this.dragDstId = null; this.dragDstId = null;
} }
} };
const clearDragSrcState = () => { const clearDragSrcState = () => {
if (this.dragSrcId) { if (this.dragSrcId) {
graph.setItemState(this.dragSrcId, 'dragSrc', false); graph.setItemState(this.dragSrcId, "dragSrc", false);
this.dragSrcId = null; this.dragSrcId = null;
} }
} };
graph.on('node:dragstart', (e: G6GraphEvent) => { graph.on("node:dragstart", (e: G6GraphEvent) => {
this.dragSrcId = e.item.getID(); this.dragSrcId = e.item.getID();
graph.setItemState(this.dragSrcId, 'dragSrc', true); graph.setItemState(this.dragSrcId, "dragSrc", true);
}); });
graph.on('node:dragend', (e: G6GraphEvent) => { graph.on("node:dragend", (e: G6GraphEvent) => {
if (this.dragSrcId) { if (this.dragSrcId) {
graph.setItemState(this.dragSrcId, 'dragSrc', false); graph.setItemState(this.dragSrcId, "dragSrc", false);
this.dragSrcId = null; this.dragSrcId = null;
} }
}); });
graph.on('node:dragover', (e: G6GraphEvent) => { graph.on("node:dragover", (e: G6GraphEvent) => {
const dstNodeId = e.item.getID(); const dstNodeId = e.item.getID();
if (dstNodeId == this.dragSrcId) { if (dstNodeId == this.dragSrcId) {
return; return;
} }
if (this.dragDstId) { if (this.dragDstId) {
graph.setItemState(this.dragDstId, 'dragRight', false); graph.setItemState(this.dragDstId, "dragRight", false);
graph.setItemState(this.dragDstId, 'dragDown', false); graph.setItemState(this.dragDstId, "dragDown", false);
graph.setItemState(this.dragDstId, 'dragUp', false); graph.setItemState(this.dragDstId, "dragUp", false);
} }
const box = e.item.getBBox(); const box = e.item.getBBox();
if (e.x > box.minX + box.width * 0.6) { if (e.x > box.minX + box.width * 0.6) {
graph.setItemState(dstNodeId, 'dragRight', true); graph.setItemState(dstNodeId, "dragRight", true);
} else if (e.y > box.minY + box.height * 0.5) { } else if (e.y > box.minY + box.height * 0.5) {
graph.setItemState(dstNodeId, 'dragDown', true); graph.setItemState(dstNodeId, "dragDown", true);
} else { } else {
graph.setItemState(dstNodeId, 'dragUp', true); graph.setItemState(dstNodeId, "dragUp", true);
} }
this.dragDstId = dstNodeId; this.dragDstId = dstNodeId;
}); });
graph.on('node:dragleave', (e: G6GraphEvent) => { graph.on("node:dragleave", (e: G6GraphEvent) => {
clearDragDstState(); clearDragDstState();
}) });
graph.on('node:drop', (e: G6GraphEvent) => { graph.on("node:drop", (e: G6GraphEvent) => {
const srcNodeId = this.dragSrcId; const srcNodeId = this.dragSrcId;
const dstNode = e.item; const dstNode = e.item;
var dragDir; var dragDir;
if (dstNode.hasState('dragRight')) { if (dstNode.hasState("dragRight")) {
dragDir = 'dragRight'; dragDir = "dragRight";
} else if (dstNode.hasState('dragDown')) { } else if (dstNode.hasState("dragDown")) {
dragDir = 'dragDown'; dragDir = "dragDown";
} else if (dstNode.hasState('dragUp')) { } else if (dstNode.hasState("dragUp")) {
dragDir = 'dragUp'; dragDir = "dragUp";
} }
clearDragSrcState(); clearDragSrcState();
@@ -196,7 +202,7 @@ export default class Editor extends React.Component<EditorProps, EditorState> {
return; return;
} }
const rootData = graph.findDataById('1'); const rootData = graph.findDataById("1");
const srcData = graph.findDataById(srcNodeId); const srcData = graph.findDataById(srcNodeId);
const srcParent = Utils.findParent(rootData, srcNodeId); const srcParent = Utils.findParent(rootData, srcNodeId);
const dstData = graph.findDataById(dstNode.getID()); const dstData = graph.findDataById(dstNode.getID());
@@ -213,28 +219,28 @@ export default class Editor extends React.Component<EditorProps, EditorState> {
} }
const removeSrc = () => { const removeSrc = () => {
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);
if (dragDir == 'dragRight') { if (dragDir == "dragRight") {
removeSrc(); removeSrc();
if (!dstData.children) { if (!dstData.children) {
dstData.children = []; dstData.children = [];
} }
dstData.children.push(srcData); dstData.children.push(srcData);
} else if (dragDir == 'dragUp') { } else if (dragDir == "dragUp") {
if (!dstParent) { if (!dstParent) {
return; return;
} }
removeSrc(); removeSrc();
const idx = dstParent.children.findIndex(e => e.id == dstData.id); const idx = dstParent.children.findIndex((e) => e.id == dstData.id);
dstParent.children.splice(idx, 0, srcData); dstParent.children.splice(idx, 0, srcData);
} else if (dragDir == 'dragDown') { } else if (dragDir == "dragDown") {
if (!dstParent) { if (!dstParent) {
return; return;
} }
removeSrc(); removeSrc();
const idx = dstParent.children.findIndex(e => e.id == dstData.id); const idx = dstParent.children.findIndex((e) => e.id == dstData.id);
dstParent.children.splice(idx + 1, 0, srcData); dstParent.children.splice(idx + 1, 0, srcData);
} else { } else {
return; return;
@@ -246,14 +252,14 @@ export default class Editor extends React.Component<EditorProps, EditorState> {
const settings = Utils.getRemoteSettings(); const settings = Utils.getRemoteSettings();
const str = fs.readFileSync(this.props.filepath, 'utf8'); const str = fs.readFileSync(this.props.filepath, "utf8");
let tree: BehaviorTreeModel = JSON.parse(str); let tree: BehaviorTreeModel = JSON.parse(str);
const data = Utils.createTreeData(tree.root, settings); const data = Utils.createTreeData(tree.root, settings);
this.autoId = Utils.refreshNodeId(data); this.autoId = Utils.refreshNodeId(data);
graph.data(data); graph.data(data);
graph.render(); graph.render();
graph.fitCenter(); graph.fitCenter();
graph.set('animate', true); graph.set("animate", true);
this.graph = graph; this.graph = graph;
@@ -264,12 +270,12 @@ export default class Editor extends React.Component<EditorProps, EditorState> {
const graph = this.graph; const graph = this.graph;
if (this.state.curNodeId) { if (this.state.curNodeId) {
graph.setItemState(this.state.curNodeId, 'selected', false); graph.setItemState(this.state.curNodeId, "selected", false);
} }
this.setState({ curNodeId }); this.setState({ curNodeId });
if (this.state.curNodeId) { if (this.state.curNodeId) {
graph.setItemState(this.state.curNodeId, 'selected', true); graph.setItemState(this.state.curNodeId, "selected", true);
} }
} }
@@ -284,7 +290,7 @@ export default class Editor extends React.Component<EditorProps, EditorState> {
const newNodeData: BehaviorNodeModel = { const newNodeData: BehaviorNodeModel = {
id: this.autoId++, id: this.autoId++,
name: name, name: name,
} };
if (!curNodeData.children) { if (!curNodeData.children) {
curNodeData.children = []; curNodeData.children = [];
} }
@@ -299,15 +305,15 @@ export default class Editor extends React.Component<EditorProps, EditorState> {
return; return;
} }
if(curNodeId == '1') { if (curNodeId == "1") {
message.warn("根节点不能删除!"); message.warn("根节点不能删除!");
return; return;
} }
this.onSelectNode(null); this.onSelectNode(null);
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();
} }
@@ -317,20 +323,23 @@ export default class Editor extends React.Component<EditorProps, EditorState> {
} }
changeWithoutAnim() { changeWithoutAnim() {
this.graph.set('animate', false); this.graph.set("animate", false);
this.graph.changeData(); this.graph.changeData();
this.graph.layout(); this.graph.layout();
this.graph.set('animate', true); this.graph.set("animate", true);
} }
save() { save() {
const { filepath } = this.props; const { filepath } = this.props;
const root = Utils.createFileData(this.graph.findDataById('1') as GraphNodeModel); const root = Utils.createFileData(this.graph.findDataById("1") as GraphNodeModel);
fs.writeFileSync(filepath, JSON.stringify({ fs.writeFileSync(
filepath,
JSON.stringify({
name: path.basename(filepath).slice(0, -5), name: path.basename(filepath).slice(0, -5),
root, root,
desc: root.desc, desc: root.desc,
})); })
);
} }
copyNode() { copyNode() {
@@ -352,15 +361,15 @@ export default class Editor extends React.Component<EditorProps, EditorState> {
const curNodeData = this.graph.findDataById(curNodeId); const curNodeData = this.graph.findDataById(curNodeId);
try { try {
const str = clipboard.readText(); const str = clipboard.readText();
if(!str || str == '') { if (!str || str == "") {
return; return;
} }
const data = JSON.parse(str); const data = JSON.parse(str);
if(!curNodeData.children) { if (!curNodeData.children) {
curNodeData.children = []; curNodeData.children = [];
} }
curNodeData.children.push(data); curNodeData.children.push(data);
this.autoId = Utils.refreshNodeId(this.graph.findDataById('1') as GraphNodeModel); this.autoId = Utils.refreshNodeId(this.graph.findDataById("1") as GraphNodeModel);
this.changeWithoutAnim(); this.changeWithoutAnim();
} catch (error) { } catch (error) {
message.error("粘贴数据有误"); message.error("粘贴数据有误");
@@ -377,14 +386,9 @@ export default class Editor extends React.Component<EditorProps, EditorState> {
return ( return (
<div className="editor"> <div className="editor">
<Row className="editorBd"> <Row className="editorBd">
<Col <Col span={18} className="editorContent" ref={this.ref} />
span={18}
className="editorContent"
ref={this.ref}
/>
<Col span={6} className="editorSidebar"> <Col span={6} className="editorSidebar">
{ {curNode ? (
curNode ?
<NodePanel <NodePanel
model={curNode} model={curNode}
settings={settings} settings={settings}
@@ -399,11 +403,9 @@ export default class Editor extends React.Component<EditorProps, EditorState> {
item.draw(); item.draw();
}} }}
/> />
: ) : (
<TreePanel <TreePanel model={treeModel} />
model={treeModel} )}
/>
}
</Col> </Col>
</Row> </Row>
</div> </div>
+15 -25
View File
@@ -1,7 +1,7 @@
import React, { Component } from "react"; import React, { Component } from "react";
import { Menu, Input } from "antd"; import { Menu, Input } from "antd";
import * as fs from 'fs'; import * as fs from "fs";
import * as path from 'path'; import * as path from "path";
import { ipcRenderer } from "electron"; import { ipcRenderer } from "electron";
import MainEventType from "../common/MainEventType"; import MainEventType from "../common/MainEventType";
@@ -18,15 +18,15 @@ export interface PropertiesProps {
} }
interface PropertiesState { interface PropertiesState {
treeList: TreeFile[] treeList: TreeFile[];
} }
export default class Properties extends Component<PropertiesProps> { export default class Properties extends Component<PropertiesProps> {
state: PropertiesState = { state: PropertiesState = {
treeList: [] treeList: [],
}; };
curWorkdir: string = ''; curWorkdir: string = "";
shouldComponentUpdate(nextProps: PropertiesProps) { shouldComponentUpdate(nextProps: PropertiesProps) {
const shouldUpdate = this.curWorkdir != nextProps.workdir; const shouldUpdate = this.curWorkdir != nextProps.workdir;
@@ -42,14 +42,14 @@ export default class Properties extends Component<PropertiesProps> {
}); });
var workdir = this.props.workdir; var workdir = this.props.workdir;
if (workdir == '') { if (workdir == "") {
return; return;
} }
this.setState({ treeList: this.getTreeList(workdir) }); this.setState({ treeList: this.getTreeList(workdir) });
} }
getTreeList(workdir: string) { getTreeList(workdir: string) {
if (workdir == '' || !fs.existsSync(workdir)) { if (workdir == "" || !fs.existsSync(workdir)) {
console.log("workdir not exist", workdir); console.log("workdir not exist", workdir);
return []; return [];
} }
@@ -57,15 +57,15 @@ export default class Properties extends Component<PropertiesProps> {
const files = fs.readdirSync(workdir); const files = fs.readdirSync(workdir);
const list: TreeFile[] = []; const list: TreeFile[] = [];
files.forEach((filename) => { files.forEach((filename) => {
const stat = fs.statSync(path.join(workdir, filename)) const stat = fs.statSync(path.join(workdir, filename));
if (stat.isFile()) { if (stat.isFile()) {
var name = filename.slice(0, -5) var name = filename.slice(0, -5);
list.push({ list.push({
name, name,
path: workdir + '/' + name + '.json' path: workdir + "/" + name + ".json",
}); });
} }
}) });
return list; return list;
} }
@@ -75,25 +75,15 @@ export default class Properties extends Component<PropertiesProps> {
const treeList = this.getTreeList(workdir); const treeList = this.getTreeList(workdir);
return ( return (
<div> <div>
<Search <Search placeholder="Search" onChange={() => {}} />
placeholder="Search" <Menu mode="inline">
onChange={() => {
}}
/>
<Menu
mode="inline"
>
{treeList.map((tree) => ( {treeList.map((tree) => (
<Menu.Item <Menu.Item key={tree.name} onClick={() => onOpenTree(tree.path)}>
key={tree.name}
onClick={() => onOpenTree(tree.path)}
>
{tree.name} {tree.name}
</Menu.Item> </Menu.Item>
))} ))}
</Menu> </Menu>
</div> </div>
) );
} }
} }
+80 -82
View File
@@ -1,78 +1,77 @@
import G6 from '@antv/g6'; import G6 from "@antv/g6";
import Settings from '../main-process/Settings'; import Settings from "../main-process/Settings";
const NODE_COLORS: any = { const NODE_COLORS: any = {
['Composite']: 'rgb(91,237,32)', ["Composite"]: "rgb(91,237,32)",
['Decorator']: 'rgb(218,167,16)', ["Decorator"]: "rgb(218,167,16)",
['Condition']: 'rgb(228,20,139)', ["Condition"]: "rgb(228,20,139)",
['Action']: 'rgb(91,143,249)', ["Action"]: "rgb(91,143,249)",
['Other']: 'rgb(112,112,112)', ["Other"]: "rgb(112,112,112)",
} };
export default function (settings: Settings) { export default function (settings: Settings) {
const collapseStyle: any = { const collapseStyle: any = {
'collapse-icon': { "collapse-icon": {
// symbol: G6.Marker.expand, // symbol: G6.Marker.expand,
fill: 'blue', fill: "blue",
} },
}; };
G6.registerNode( G6.registerNode(
'TreeNode', "TreeNode",
{ {
options: { options: {
type: 'rect', type: "rect",
labelCfg: { labelCfg: {
style: { style: {
fill: 'blue', fill: "blue",
fontSize: 10 fontSize: 10,
} },
}, },
style: { style: {
fill: "white", fill: "white",
}, },
stateStyles: { stateStyles: {
selected: { selected: {
'main-box': { "main-box": {
stroke: 'yellow', stroke: "yellow",
lineWidth: 5, lineWidth: 5,
}, },
}, },
hover: { hover: {
stroke: 'white', stroke: "white",
lineWidth: 3, lineWidth: 3,
}, },
dragSrc: { dragSrc: {
fill: 'gray', fill: "gray",
}, },
dragRight: { dragRight: {
'drag-right': { "drag-right": {
fillOpacity: 0.6, fillOpacity: 0.6,
} },
}, },
dragUp: { dragUp: {
'drag-up': { "drag-up": {
fillOpacity: 0.6, fillOpacity: 0.6,
} },
}, },
dragDown: { dragDown: {
'drag-down': { "drag-down": {
fillOpacity: 0.6, fillOpacity: 0.6,
} },
} },
}, },
}, },
draw(cfg, group) { draw(cfg, group) {
const nodeConf = settings.getNodeConf(cfg.name as string); const nodeConf = settings.getNodeConf(cfg.name as string);
const classify = nodeConf.type || 'Other'; const classify = nodeConf.type || "Other";
const color = NODE_COLORS[classify] || 'Other'; const color = NODE_COLORS[classify] || "Other";
var size = cfg.size ? cfg.size as number[] : [150, 40]; var size = cfg.size ? (cfg.size as number[]) : [150, 40];
const w = size[0]; const w = size[0];
const h = size[1]; const h = size[1];
const x0 = -w / 2; const x0 = -w / 2;
const y0 = -h / 2; const y0 = -h / 2;
const r = 2; const r = 2;
const shape = group.addShape('rect', { const shape = group.addShape("rect", {
attrs: { attrs: {
x: x0, x: x0,
y: y0, y: y0,
@@ -80,15 +79,15 @@ export default function (settings: Settings) {
height: h, height: h,
stroke: color, stroke: color,
lineWidth: 2, lineWidth: 2,
fill: 'white', fill: "white",
radius: r, radius: r,
}, },
name: 'main-box', name: "main-box",
draggable: true, draggable: true,
}); });
// name bg // name bg
group.addShape('rect', { group.addShape("rect", {
attrs: { attrs: {
x: x0 + 1.5, x: x0 + 1.5,
y: y0 + 1.5, y: y0 + 1.5,
@@ -97,30 +96,30 @@ export default function (settings: Settings) {
fill: color, fill: color,
// radius: r, // radius: r,
}, },
name: 'name-bg', name: "name-bg",
draggable: true, draggable: true,
}); });
// id text // id text
group.addShape('text', { group.addShape("text", {
attrs: { attrs: {
textBaseline: 'top', textBaseline: "top",
x: x0 - 3, x: x0 - 3,
y: -8, y: -8,
fontSize: 20, fontSize: 20,
lineHeight: 20, lineHeight: 20,
text: cfg.id, text: cfg.id,
textAlign: 'right', textAlign: "right",
fill: 'white', fill: "white",
stroke: 'black', stroke: "black",
lineWidth: 2, lineWidth: 2,
}, },
name: 'id-text', name: "id-text",
}); });
// icon // icon
var img = `./static/icons/${classify}.svg`; var img = `./static/icons/${classify}.svg`;
group.addShape('image', { group.addShape("image", {
attrs: { attrs: {
x: x0 + 3, x: x0 + 3,
y: y0 + 2, y: y0 + 2,
@@ -128,21 +127,21 @@ export default function (settings: Settings) {
width: 14, width: 14,
img, img,
}, },
name: 'node-icon', name: "node-icon",
}); });
// name text // name text
group.addShape('text', { group.addShape("text", {
attrs: { attrs: {
textBaseline: 'top', textBaseline: "top",
x: x0 + 18, x: x0 + 18,
y: y0 + 4, y: y0 + 4,
fontWeight: 800, fontWeight: 800,
lineHeight: 20, lineHeight: 20,
text: cfg.name, text: cfg.name,
fill: 'black', fill: "black",
}, },
name: 'name-text', name: "name-text",
}); });
var x = x0 + 2; var x = x0 + 2;
@@ -150,128 +149,127 @@ export default function (settings: Settings) {
// desc text // desc text
const desc = cfg.desc || nodeConf.desc; const desc = cfg.desc || nodeConf.desc;
if (desc) { if (desc) {
group.addShape('text', { group.addShape("text", {
attrs: { attrs: {
textBaseline: 'top', textBaseline: "top",
x, x,
y, y,
lineHeight: 20, lineHeight: 20,
fontWeight: 800, fontWeight: 800,
text: `备注:${desc}`, text: `备注:${desc}`,
fill: 'black', fill: "black",
}, },
name: 'desc-text', name: "desc-text",
}); });
} }
const args: any = cfg.args; const args: any = cfg.args;
if (nodeConf.args && args && Object.keys(args).length > 0) { if (nodeConf.args && args && Object.keys(args).length > 0) {
y += 20; y += 20;
group.addShape('text', { group.addShape("text", {
attrs: { attrs: {
textBaseline: 'top', textBaseline: "top",
x, x,
y, y,
lineHeight: 20, lineHeight: 20,
text: `参数:${JSON.stringify(args)}`, text: `参数:${JSON.stringify(args)}`,
fill: 'black', fill: "black",
}, },
name: 'args-text', name: "args-text",
}); });
} }
const input: [] = cfg.input ? cfg.input as [] : []; const input: [] = cfg.input ? (cfg.input as []) : [];
if (nodeConf.input && input.length > 0) { if (nodeConf.input && input.length > 0) {
y += 20; y += 20;
group.addShape('text', { group.addShape("text", {
attrs: { attrs: {
textBaseline: 'top', textBaseline: "top",
x, x,
y, y,
lineHeight: 20, lineHeight: 20,
text: `输入:${JSON.stringify(input)}`, text: `输入:${JSON.stringify(input)}`,
fill: 'black', fill: "black",
}, },
name: 'input-text', name: "input-text",
}); });
} }
const output: [] = cfg.output ? cfg.output as [] : []; const output: [] = cfg.output ? (cfg.output as []) : [];
if (nodeConf.output && output.length > 0) { if (nodeConf.output && output.length > 0) {
y += 20; y += 20;
group.addShape('text', { group.addShape("text", {
attrs: { attrs: {
textBaseline: 'top', textBaseline: "top",
x, x,
y, y,
lineHeight: 20, lineHeight: 20,
text: `输出:${JSON.stringify(output)}`, text: `输出:${JSON.stringify(output)}`,
fill: 'black', fill: "black",
}, },
name: 'output-text', name: "output-text",
}); });
} }
if (Array.isArray(cfg.children) && cfg.children.length > 0) { if (Array.isArray(cfg.children) && cfg.children.length > 0) {
group.addShape('marker', { group.addShape("marker", {
attrs: { attrs: {
x: w / 2, x: w / 2,
y: 0, y: 0,
r: 6, r: 6,
symbol: G6.Marker.collapse, symbol: G6.Marker.collapse,
stroke: '#666', stroke: "#666",
lineWidth: 1, lineWidth: 1,
fill: '#fff', fill: "#fff",
}, },
name: 'collapse-icon', name: "collapse-icon",
}); });
} }
group.addShape("rect", {
group.addShape('rect', { name: "drag-up",
name: 'drag-up',
attrs: { attrs: {
x: -w / 2, x: -w / 2,
y: -h / 2, y: -h / 2,
width: w, width: w,
height: h / 2, height: h / 2,
fill: 'blue', fill: "blue",
fillOpacity: 0, fillOpacity: 0,
}, },
draggable: true, draggable: true,
// visible: false, // visible: false,
}); });
group.addShape('rect', { group.addShape("rect", {
name: 'drag-down', name: "drag-down",
attrs: { attrs: {
x: -w / 2, x: -w / 2,
y: 0, y: 0,
width: w, width: w,
height: h / 2, height: h / 2,
fill: 'blue', fill: "blue",
fillOpacity: 0, fillOpacity: 0,
}, },
draggable: true, draggable: true,
// visible: false, // visible: false,
}); });
group.addShape('rect', { group.addShape("rect", {
name: 'drag-right', name: "drag-right",
attrs: { attrs: {
x: w * 0.1, x: w * 0.1,
y: -h / 2, y: -h / 2,
width: w * 0.4, width: w * 0.4,
height: h, height: h,
fill: 'blue', fill: "blue",
fillOpacity: 0, fillOpacity: 0,
}, },
draggable: true, draggable: true,
// visible: false, // visible: false,
}); });
return shape; return shape;
}
}, },
'single-node', },
"single-node"
); );
} }
+18 -24
View File
@@ -1,16 +1,15 @@
import Editor from "./Editor"; import Editor from "./Editor";
import React, { Component } from "react"; import React, { Component } from "react";
import { Layout, Tabs, message } from 'antd'; import { Layout, Tabs, message } from "antd";
import { ipcRenderer, remote } from 'electron'; import { ipcRenderer, remote } from "electron";
import * as path from 'path'; import * as path from "path";
import 'antd/dist/antd.dark.css'; import "antd/dist/antd.dark.css";
import MainEventType from "../common/MainEventType"; import MainEventType from "../common/MainEventType";
const { TabPane } = Tabs; const { TabPane } = Tabs;
interface TreeTabsProps { interface TreeTabsProps {}
}
interface TreeTabsState { interface TreeTabsState {
filepaths: string[]; filepaths: string[];
@@ -20,12 +19,11 @@ interface TreeTabsState {
export default class TreeTabs extends Component<TreeTabsProps, TreeTabsState> { export default class TreeTabs extends Component<TreeTabsProps, TreeTabsState> {
state: TreeTabsState = { state: TreeTabsState = {
filepaths: [], filepaths: [],
} };
editors: { [path: string]: Editor } = {} editors: { [path: string]: Editor } = {};
componentWillMount() { componentWillMount() {}
}
componentDidMount() { componentDidMount() {
ipcRenderer.on(MainEventType.CREATE_NODE, (event: any, name: any) => { ipcRenderer.on(MainEventType.CREATE_NODE, (event: any, name: any) => {
@@ -90,7 +88,7 @@ export default class TreeTabs extends Component<TreeTabsProps, TreeTabsState> {
console.log("render tabs"); console.log("render tabs");
const { filepaths, curPath } = this.state; const { filepaths, curPath } = this.state;
if (!curPath) { if (!curPath) {
return (<div />); return <div />;
} }
return ( return (
<Tabs <Tabs
@@ -99,11 +97,11 @@ export default class TreeTabs extends Component<TreeTabsProps, TreeTabsState> {
type="editable-card" type="editable-card"
defaultActiveKey={curPath} defaultActiveKey={curPath}
activeKey={curPath} activeKey={curPath}
onChange={activeKey => { onChange={(activeKey) => {
this.setState({ curPath: activeKey }) this.setState({ curPath: activeKey });
}} }}
onEdit={(targetKey, action) => { onEdit={(targetKey, action) => {
if (action == 'remove') { if (action == "remove") {
const idx = filepaths.indexOf(targetKey as string); const idx = filepaths.indexOf(targetKey as string);
if (idx < 0) { if (idx < 0) {
return; return;
@@ -114,23 +112,19 @@ export default class TreeTabs extends Component<TreeTabsProps, TreeTabsState> {
} }
}} }}
> >
{ {filepaths.map((filepath) => {
filepaths.map(filepath => {
return ( return (
<TabPane tab={path.basename(filepath)} key={filepath}> <TabPane tab={path.basename(filepath)} key={filepath}>
<Editor <Editor
filepath={filepath} filepath={filepath}
ref={ ref={(ref) => {
ref => {
this.editors[filepath] = ref; this.editors[filepath] = ref;
} }}
}
/> />
</TabPane> </TabPane>
); );
}) })}
}
</Tabs> </Tabs>
) );
} }
}; }
+15 -20
View File
@@ -1,19 +1,18 @@
import * as ReactDOM from "react-dom"; import * as ReactDOM from "react-dom";
import Editor from "./Editor"; import Editor from "./Editor";
import React, { Component } from "react"; import React, { Component } from "react";
import { Layout, Tabs } from 'antd'; import { Layout, Tabs } from "antd";
import { ipcRenderer, remote } from 'electron'; import { ipcRenderer, remote } from "electron";
import * as path from 'path'; import * as path from "path";
import * as fs from 'fs'; import * as fs from "fs";
import * as Utils from '../common/Utils'; import * as Utils from "../common/Utils";
import MainEventType from "../common/MainEventType"; import MainEventType from "../common/MainEventType";
import Properties from "./Properties"; import Properties from "./Properties";
import Settings from "../main-process/Settings"; import Settings from "../main-process/Settings";
import G6 from '@antv/g6'; import G6 from "@antv/g6";
import 'antd/dist/antd.dark.css'; import "antd/dist/antd.dark.css";
import './index.css'; import "./index.css";
import { ModelConfig, Item } from "@antv/g6/lib/types"; import { ModelConfig, Item } from "@antv/g6/lib/types";
import RegisterNode from "./RegisterNode"; import RegisterNode from "./RegisterNode";
import TreeTabs from "./TreeTabs"; import TreeTabs from "./TreeTabs";
@@ -21,7 +20,6 @@ import TreeTabs from "./TreeTabs";
const { Header, Sider, Content, Footer } = Layout; const { Header, Sider, Content, Footer } = Layout;
const { TabPane } = Tabs; const { TabPane } = Tabs;
interface MainState { interface MainState {
workdir: string; workdir: string;
workspace: string; workspace: string;
@@ -29,9 +27,9 @@ interface MainState {
export default class Main extends Component { export default class Main extends Component {
state: MainState = { state: MainState = {
workdir: '', workdir: "",
workspace: '', workspace: "",
} };
settings: Settings; settings: Settings;
tabs: TreeTabs; tabs: TreeTabs;
@@ -79,17 +77,14 @@ export default class Main extends Component {
</Sider> </Sider>
<Content className="content"> <Content className="content">
<TreeTabs <TreeTabs
ref={ref => { ref={(ref) => {
this.tabs = ref; this.tabs = ref;
}} }}
/> />
</Content> </Content>
</Layout> </Layout>
) );
} }
}; }
ReactDOM.render( ReactDOM.render(<Main />, document.getElementById("root") as HTMLElement);
<Main />,
document.getElementById('root') as HTMLElement
);