!469 右侧模板参数对撤销的支持

pull/469/MERGE
肖诗雅 5 years ago committed by ChenX
parent 3e2fc9afcf
commit cb0ec05a29

@ -0,0 +1,47 @@
import { copyTextToClipboard } from "../../Common/Utils";
import { ObjectId } from "../../DatabaseServices/ObjectId";
import { DeleteTempate } from "../../DatabaseServices/Template/TempateUtils";
import { TemplateRecord } from "../../DatabaseServices/Template/TemplateRecord";
import { SelectTempate } from "../../DatabaseServices/Template/TemplateTest";
import { Command, commandMachine } from "../../Editor/CommandMachine";
import { HotCMD } from "../../Hot/HotCommand";
@HotCMD
export class Command_DeleteTemplate implements Command
{
async exec()
{
let temp = await SelectTempate();
if (!temp) return;
DeleteTempate(temp);
}
}
@HotCMD
export class Command_Template2Tree implements Command
{
async exec()
{
let temp = await SelectTempate();
if (!temp) return;
temp = temp.Root;
console.log(JSON.stringify(TemplateToTree(temp.Id), null, 2));
}
}
interface Node
{
id: number;
children: Node[];
}
function TemplateToTree(temp: ObjectId): Node
{
let record = temp.Object as TemplateRecord;
let node = { id: temp.Index, children: record.Children.filter(id => !id.IsErase).map(TemplateToTree) };
return node;
}
commandMachine.RegisterCommand("t2tree", new Command_Template2Tree())

@ -1,6 +1,7 @@
import { Intent } from "@blueprintjs/core";
import { Box3, Color, Matrix4, Scene, Vector3 } from "three";
import { app } from "../../ApplicationServices/Application";
import { arrayRemoveOnce } from "../../Common/ArrayExt";
import { DisposeThreeObj } from "../../Common/Dispose";
import { TemplateUrls } from "../../Common/HostUrl";
import { PostJson, RequestStatus, uploadLogo } from "../../Common/Request";
@ -20,6 +21,7 @@ import { AppToaster } from "../../UI/Components/Toaster";
import { CADFiler } from "../CADFiler";
import { Database } from "../Database";
import { Board } from "../Entity/Board";
import { Entity } from "../Entity/Entity";
import { Polyline } from "../Entity/Polyline";
import { ObjectId } from "../ObjectId";
import { TempateThicknessAction, ThicknessActionData, ThicknessDirection } from "./Action/TempateThicknessAction";
@ -931,3 +933,23 @@ export async function UploadUpdateTemplate(template: TemplateRecord, templateId:
}
return false;
}
/**
* ,
*/
export function DeleteTempate(template: TemplateRecord)
{
template.Traverse(t =>
{
for (let id of t.Objects)
{
if (!id.IsErase)
{
let e = id.Object as Entity;
e.Erase();
}
}
t.Erase();
});
}

@ -1,4 +1,5 @@
import { Box3, Math, Matrix4, Vector3 } from "three";
import { arrayRemoveOnce } from "../../Common/ArrayExt";
import { AutoRecord, ISPROXYKEY } from "../AutoRecord";
import { Factory } from "../CADFactory";
import { CADFiler } from "../CADFiler";
@ -116,6 +117,10 @@ export class TemplateRecord extends SymbolTableRecord
{
if (key === ISPROXYKEY)
return true;
else if (key === "splice")
this.WriteAllObjectRecord();
else if (key === "pop")
this.WriteAllObjectRecord();
return Reflect.get(target, key, receiver);
}
});

@ -129,6 +129,7 @@ import { CommandServer } from "../DatabaseServices/CommandServer";
import { AutoTempateSizeAction } from "../DatabaseServices/Template/TemplateTest";
import { ICommand } from "../UI/Components/CommandPanel/CommandList";
import { commandMachine } from "./CommandMachine";
import { Command_DeleteTemplate } from "../Add-on/testEntity/TestTemplateDelete";
export function registerCommand()
{
@ -348,8 +349,8 @@ export function registerCommand()
commandMachine.RegisterCommand("template", new ShowTemplate());
commandMachine.RegisterCommand("templatedesign", new ShowTemplateDesign());
commandMachine.RegisterCommand("TemplateSearch", new Command_TemplateSearch());
commandMachine.RegisterCommand("templateDelete", new Command_DeleteTemplate());
RegistCustomCommand();
}

@ -83,7 +83,7 @@ export class RightPanel extends React.Component<{ store?: RightPanelStore }>
<Tab className="tab-unstyle" id={RightTabId.Drill} title="排 钻" panel={<DrillingComponent />} />
<Tab className="tab-unstyle" id={RightTabId.Scene} title="场 景" panel={<ScenePanel />} />
<Tab className="tab-unstyle" id={RightTabId.Material} title="材 质" panel={<MaterialExplorer materialTable={app.Database.MaterialTable}></MaterialExplorer>} />
<Tab className="tab-unstyle" id={RightTabId.TemplateParam} title="模板参数" panel={<TemplateParamPanel template={store.currentTemplate} />} />
<Tab className="tab-unstyle" id={RightTabId.TemplateParam} title="模板参数" panel={<TemplateParamPanel selectTemplateId={store.currentTemplateIndex} />} />
<Tab className="tab-unstyle" id={RightTabId.Template} title="模 板" panel={<BoardTemplatePanel />} />
<Tab className="tab-unstyle" id={RightTabId.Accessories} title="配 件" />
</ Tabs>

@ -5,6 +5,9 @@
.bp3-tree{
height: 100%;
overflow: auto;
.bp3-tree-node-content{
height: 20px;
}
}
}
.template-detail {

@ -1,80 +1,120 @@
import React from "react";
import { observer, inject } from "mobx-react";
import { TemplateRecord } from "../../../DatabaseServices/Template/TemplateRecord";
import { TemplateParam } from "../../../DatabaseServices/Template/Param/TemplateParam";
import { INeedUpdateParams } from "../Template/TemplateComponent";
import { Button, Classes, ContextMenu, H5, Intent, ITreeNode, Menu, MenuItem, Tree } from "@blueprintjs/core";
import { observable } from "mobx";
import { H5, Tree, ITreeNode, Classes, ContextMenu, Menu, MenuItem, Intent, Button } from "@blueprintjs/core";
import { app } from "../../../ApplicationServices/Application";
import { Entity } from "../../../DatabaseServices/Entity/Entity";
import { observer } from "mobx-react";
import React from "react";
import { Object3D } from "three";
import { Board } from "../../../DatabaseServices/Entity/Board";
import { end } from "xaop";
import { app } from "../../../ApplicationServices/Application";
import { arrayRemoveOnce } from "../../../Common/ArrayExt";
import { EBoardKeyList } from "../../../Common/BoardKeyList";
import { FixedNotZero } from "../../../Common/Utils";
import { safeEval } from "../../../Common/eval";
import { CommandWrap } from "../../../Editor/CommandMachine";
import { FixedNotZero } from "../../../Common/Utils";
import { CommandHistoryRecord } from "../../../DatabaseServices/CommandHistoryRecord";
import { Board } from "../../../DatabaseServices/Entity/Board";
import { Entity } from "../../../DatabaseServices/Entity/Entity";
import { PositioningClampSpace } from "../../../DatabaseServices/Template/Positioning/PositioningClampSpace";
import { DeleteTempate } from "../../../DatabaseServices/Template/TempateUtils";
import { TemplateRecord } from "../../../DatabaseServices/Template/TemplateRecord";
import { TemplateSplitType } from "../../../DatabaseServices/Template/TemplateType";
import { end } from "xaop";
import { CommandHistoryRecord } from "../../../DatabaseServices/CommandHistoryRecord";
import { CommandWrap } from "../../../Editor/CommandMachine";
import { INeedUpdateParams } from "../Template/TemplateComponent";
interface TemplateParamState
{
nodes: ITreeNode[];//目录节点
nodes: ITreeNode[];//节点
}
interface TemplateParamProps
{
selectTemplateId: number;
}
@inject('template')
@observer
export class TemplateParamPanel extends React.Component<{ template: TemplateRecord }, TemplateParamState>
export class TemplateParamPanel extends React.Component<TemplateParamProps, TemplateParamState>
{
//被展示的模板
@observable private currentTemplate: TemplateRecord = this.props.template;
//展示模块树的根节点
private displayTemplateRootId: number;
//当前选中的节点模块id,可能被删除.
private currentTemplateId: number;
//TemplateDetail组件的Props 用于展示模板数据
@observable private params: TemplateParam[] = [];
@observable private currentProps: INeedUpdateParams[] = [];
//记录需要在模板树UI中亮显的节点
private needSelectedNode: ITreeNode;
//UI交互相关变量
@observable private currentTreePathNum: number[] = [];
//移除注入
private removeFuncs: Function[] = [];
constructor(props)
{
super(props);
this.state = { nodes: [], };
if (this.currentTemplate)
this.InitData(this.currentTemplate);
this.currentTemplateId = this.props.selectTemplateId;
this.InitData = this.InitData.bind(this);
}
componentDidMount()
{
const commands = ["删除模板节点", "应用参数修改", "分离空间"];
let tem = this.GetCurrentTemplate();
if (tem)
this.displayTemplateRootId = tem.Root.Id.Index;
this.InitData();
this.removeFuncs.push(
end(app.Database.hm, app.Database.hm.RedoEvent, (cmdName: string, historyRec: CommandHistoryRecord) =>
{
if (historyRec.HistoryList.has(this.props.template.Id))
this.InitData(this.props.template);
if (commands.includes(cmdName))
this.InitData();
}),
end(app.Database.hm, app.Database.hm.UndoEvent, (cmdName: string, historyRec: CommandHistoryRecord) =>
{
if (historyRec.HistoryList.has(this.props.template.Id))
this.InitData(this.props.template);
if (commands.includes(cmdName))
this.InitData();
})
);
}
componentWillUnmount()
{
for (let f of this.removeFuncs)
f();
this.removeFuncs.length = 0;
}
UNSAFE_componentWillReceiveProps(nextProps)
componentDidUpdate(prevProps: TemplateParamProps)
{
if (nextProps.template)
if (prevProps.selectTemplateId !== this.props.selectTemplateId)
{
this.InitData(nextProps.template);
this.currentTemplate = nextProps.template;
this.currentTemplateId = this.props.selectTemplateId;
let tem = this.GetCurrentTemplate();
if (tem)
this.displayTemplateRootId = tem.Root.Id.Index;
this.InitData();
}
}
//当前选中的模块记录
GetCurrentTemplate(): TemplateRecord | undefined
{
let curId = app.Database.GetObjectId(this.currentTemplateId);
if (curId === undefined || curId.IsErase)
curId = app.Database.GetObjectId(this.displayTemplateRootId);
if (!curId || curId.IsErase)
return;
return curId.Object as TemplateRecord;
}
//初始化所有展示数据
InitData = (template: TemplateRecord, updateTree: boolean = true) =>
InitData()
{
this.params = template.Params;
observable(this.currentProps).replace(this.params.map((p) =>
let temp = this.GetCurrentTemplate();
if (!temp)
{
this.setState({ nodes: [] });
return;
}
observable(this.currentProps).replace(temp.Params.map((p) =>
{
return {
name: p.name,
@ -83,57 +123,56 @@ export class TemplateParamPanel extends React.Component<{ template: TemplateReco
expr: p.expr,
}
}));
if (updateTree)
this.setState({ nodes: this.parseNodes(template, [template.Root]) });
if (this.needSelectedNode)
this.SelectNode(this.needSelectedNode);
}
//转换为节点树
private parseNodes = (curTempSelected: TemplateRecord, templates: TemplateRecord[]) =>
{
let newNodes: ITreeNode[] = [];
for (let template of templates)
let nodes = [this.Template2TreeNode(temp.Root)];
let allnodes: ITreeNode[] = [...nodes];
for (let i = 0; i < allnodes.length; i++)
{
let node: ITreeNode = {
id: template.Id.Index,
label: template.Name === "" ? "[ 空名称 ]" : template.Name,
hasCaret: template.Children.length > 0,
childNodes: this.parseNodes(curTempSelected, template.Children.map((t) => { return t.Object as TemplateRecord })),
isExpanded: true,
nodeData: template,
};
//记录被点击的模板的ITreeNode 以便亮显对应的目录树节点
newNodes.push(node);
if (curTempSelected.Id.Index === template.Id.Index)
this.needSelectedNode = node;
let n = allnodes[i];
n.isSelected = n.nodeData === temp;
allnodes.push(...n.childNodes);
}
return newNodes;
this.setState({ nodes });
}
//展开折叠目录
Template2TreeNode = (template: TemplateRecord): ITreeNode =>
{
let children = template.Children.filter(id => !id.IsErase).map(id => id.Object as TemplateRecord);
let node: ITreeNode = {
id: template.Id.Index,
label: template.Name === "" ? "[ 空名称 ]" : template.Name,
hasCaret: children.length > 0,
childNodes: children.map(this.Template2TreeNode),
isExpanded: true,
nodeData: template,
};
return node;
}
//展开折叠节点
private HandleNodeCollapse = (nodeData: ITreeNode, isCollapse: boolean) =>
{
nodeData.isExpanded = !isCollapse;
this.setState(this.state);
}
//展示右键菜单
private ShowContextMenu = (nodeData: ITreeNode, _nodePath: number[], e: React.MouseEvent<HTMLElement> | MouseEvent) =>
private ShowContextMenu = (node: ITreeNode, _nodePath: number[], e: React.MouseEvent<HTMLElement> | MouseEvent) =>
{
if (nodeData)
{
this.SelectNode(nodeData, true, true);
this.getCurrentDir(nodeData.id, _nodePath);
}
//亮显节点
let curTemp = node.nodeData as TemplateRecord;
this.currentTemplateId = curTemp.Id.Index;
this.InitData();
ContextMenu.show(
<Menu>
{
<>
<MenuItem
text="亮显空间子层"
onClick={() => { this.OutlineSpaceChild(nodeData) }}
onClick={() => { this.OutlineSpaceChild(node) }}
/>
<MenuItem
text="删除节点"
onClick={() => { this.DeleteTreeNode(nodeData) }}
onClick={() => { this.DeleteTreeNode(node) }}
/>
<MenuItem
text="切割空间"
@ -141,15 +180,15 @@ export class TemplateParamPanel extends React.Component<{ template: TemplateReco
/>
<MenuItem
text="分离空间"
onClick={() => { this.SeparateSpace(nodeData) }}
onClick={() => { this.SeparateSpace(node) }}
/>
<MenuItem
text="批量修改当前层的柜体名为节点名称"
onClick={() => { this.BatchModifyCurrentLayerCabinetName(nodeData) }}
onClick={() => { this.BatchModifyCurrentLayerCabinetName(node) }}
/>
<MenuItem
text="批量修改当前层及下的柜体名为节点名称"
onClick={() => { this.BatchModifyCurrentChildrenCabinetName(nodeData) }}
onClick={() => { this.BatchModifyCurrentChildrenCabinetName(node) }}
/>
</>
}
@ -160,18 +199,12 @@ export class TemplateParamPanel extends React.Component<{ template: TemplateReco
e.stopPropagation();
e.preventDefault();
};
//批量修改当前层的柜体名为节点名称
private BatchModifyCurrentLayerCabinetName = (nodeData: ITreeNode) =>
private BatchModifyCurrentLayerCabinetName = (node: ITreeNode) =>
{
let curTemp = nodeData.nodeData as TemplateRecord;
let parent = curTemp.Parent ? curTemp.Parent.Object as TemplateRecord : undefined;
if (!parent)
return;
parent.Children.forEach((c) =>
{
let tr = c.Object as TemplateRecord;
this.ModifyCabinetName(tr, nodeData.label as string);
})
let tem = node.nodeData as TemplateRecord;
this.ModifyCabinetName(tem, tem.Name as string);
}
//修改模板柜体名称
ModifyCabinetName = (tr: TemplateRecord, cabinetName: string) =>
@ -186,130 +219,48 @@ export class TemplateParamPanel extends React.Component<{ template: TemplateReco
}
}
//批量修改当前层及下的柜体名为节点名称
private BatchModifyCurrentChildrenCabinetName = (nodeData: ITreeNode) =>
private BatchModifyCurrentChildrenCabinetName = (node: ITreeNode) =>
{
let curTemp = nodeData.nodeData as TemplateRecord;
let curTemp = node.nodeData as TemplateRecord;
let trs = this.GetAllChildFromThisTemplate(curTemp);
for (let tr of trs)
{
this.ModifyCabinetName(tr, nodeData.label as string);
this.ModifyCabinetName(tr, curTemp.Name as string);
}
}
//获取当前目录路径
private getCurrentDir = (dirId: React.ReactText, nodePath: number[]) =>
{
let childNodes: ITreeNode[];
for (let i of nodePath)
{
let node: ITreeNode;
if (!childNodes)
node = this.state.nodes[i];
else
node = childNodes[i];
childNodes = node.childNodes;
}
this.currentTreePathNum = nodePath;
}
//点击目录
private HandleNodeClick = (nodeData: ITreeNode, _nodePath: number[], e: React.MouseEvent<HTMLElement> | MouseEvent) =>
{
this.currentTemplate = nodeData.nodeData as TemplateRecord;
this.InitData(this.currentTemplate, false);
this.SelectNode(nodeData, true, true);
};
//选中目录高亮
private SelectNode = (nodeData: ITreeNode, isSelected?: boolean, handleClick?: boolean) =>
{
const originallySelected = nodeData.isSelected;
this.forEachNode(this.state.nodes, n => (n.isSelected = false));
if (isSelected)
nodeData.isSelected = isSelected;
else
nodeData.isSelected = originallySelected == null ? true : !originallySelected;
if (handleClick)
this.setState(this.state)
}
//去掉其他节点被选择状态
private forEachNode(nodes: ITreeNode[], callback: (node: ITreeNode) => void)
//点击节点事件
private HandleNodeClick = (node: ITreeNode, _nodePath: number[], e: React.MouseEvent<HTMLElement> | MouseEvent) =>
{
if (!nodes)
return;
for (const node of nodes)
{
callback(node);
this.forEachNode(node.childNodes, callback);
}
let tem = node.nodeData as TemplateRecord;
this.currentTemplateId = tem.Id.Index;
this.InitData();
}
//获取所有模板子节点
private GetAllChildFromThisTemplate = (tr: TemplateRecord) =>
{
//从tr开始搜索它的所有子节点并加入数组 tr排最后
let trs: TemplateRecord[] = [];
tr.Traverse((node) => { trs.unshift(node) });
tr.Traverse((node) => { trs.push(node) });
return trs;
}
// 删除节点
//删除节点
private DeleteTreeNode = (nodeData: ITreeNode) =>
{
//删除模板
let curId = nodeData.id;
let tr = nodeData.nodeData as TemplateRecord;
let parent = tr.Parent ? tr.Parent.Object as TemplateRecord : undefined;
if (parent)
parent.Children = parent.Children.filter((c) => { c.Index !== curId });
//从最深处开始删除
let treeNodes = this.GetAllChildFromThisTemplate(tr);
CommandWrap(() =>
{
for (let tn of treeNodes)
{
app.Database.TemplateTable.Remove(tn);
for (let t of tn.Objects)
{
t.Object.Erase();
}
}
DeleteTempate(tr);
this.InitData();
}, "删除模板节点");
if (parent)
this.currentTemplate = this.props.template;
else
this.currentTemplate = undefined;
app.Editor.UpdateScreen();
this.DeleteUITreeNode();
}
private DeleteUITreeNode = () =>
{
//删除UI节点
let nodes = this.state.nodes;
let lastIndex = this.currentTreePathNum.pop();
let childNodes: ITreeNode[];
let lastNode: ITreeNode;
for (let i of this.currentTreePathNum)
{
if (!childNodes)
{
lastNode = nodes[i];
childNodes = nodes[i].childNodes;
}
else
{
lastNode = childNodes[i];
childNodes = childNodes[i].childNodes;
}
}
if (!childNodes)
childNodes = nodes;
childNodes.splice(lastIndex, 1);
if (lastNode)
lastNode.hasCaret = childNodes.length > 0;
this.setState({ nodes: [...nodes] })
}
//亮显空间子层
OutlineSpaceChild = (node: ITreeNode) =>
{
this.ClearSelect();
app.Editor.SelectCtrl.Cancel();
let tr = node.nodeData as TemplateRecord;
let treeNodes = this.GetAllChildFromThisTemplate(tr);
let outlineObj3ds: Object3D[] = [];
@ -324,13 +275,7 @@ export class TemplateParamPanel extends React.Component<{ template: TemplateReco
app.Viewer.OutlinePass.selectedObjects = outlineObj3ds;
app.Editor.UpdateScreen();
}
//清除当前选中
ClearSelect = () =>
{
app.Editor.SelectCtrl.SelectSet.Clear();
app.Viewer.GripScene.Clear();
app.Editor.SelectCtrl.UpdateView();
}
//切割空间 待完善
DivideSpace = () =>
{
@ -340,22 +285,24 @@ export class TemplateParamPanel extends React.Component<{ template: TemplateReco
SeparateSpace = (nodeData: ITreeNode) =>
{
//斩断其与父节点的关联
let curId = nodeData.id;
let tr = nodeData.nodeData as TemplateRecord;
let parent = tr.Parent ? tr.Parent.Object as TemplateRecord : undefined;
if (!parent)
return;
else
{
tr.Parent = undefined;
parent.Children = parent.Children.filter((c) => c.Object.Id.Index !== curId);
CommandWrap(() =>
{
tr.Parent = undefined;
arrayRemoveOnce(parent.Children, tr.Id);
}, "分离空间");
}
this.DeleteUITreeNode();
}
render()
{
let tem = this.GetCurrentTemplate();
return (
this.currentTemplate ?
tem ?
<div id="templateParam">
{/* 模板树 */}
<div
@ -372,13 +319,13 @@ export class TemplateParamPanel extends React.Component<{ template: TemplateReco
</div>
<TemplateParamDetail
updateParams={this.currentProps}
currentShowTemplate={this.currentTemplate}
currentShowTemplate={tem}
callback={this.InitData}
/>
</div>
:
<div style={{ textAlign: "center" }}>
<H5> </H5>
<H5></H5>
</div>
)
}
@ -409,8 +356,8 @@ export class TemplateParamDetail extends React.Component<{ updateParams: INeedUp
}
});
await currentShowTemplate.UpdateTemplateTree();
}, "应用参数修改")
callback(currentShowTemplate, false);
}, "应用参数修改");
callback();
}
GetAssociateBrNums = (tr: TemplateRecord) =>
{
@ -472,7 +419,7 @@ export class TemplateParamDetail extends React.Component<{ updateParams: INeedUp
{
if (POSITION_PAR.includes(par.name))
return (
<label style={{ margin: "0 5px" }}>
<label style={{ margin: "0 5px" }} onKeyDown={e => e.stopPropagation()}>
{par.name[1]}:
<input
className={Classes.INPUT}
@ -491,7 +438,7 @@ export class TemplateParamDetail extends React.Component<{ updateParams: INeedUp
{
if (ROTATION_PAR.includes(par.name))
return (
<label style={{ margin: "0 5px" }}>
<label style={{ margin: "0 5px" }} onKeyDown={e => e.stopPropagation()}>
{par.name[1]}:
<input
className={Classes.INPUT}

@ -29,7 +29,7 @@ export class RightPanelStore implements IConfigStore
@observable modelingItems: IModelingItem[] = [];
@observable UIModelingItems: IUIModeiling[] = [];
@observable currentBoard: Board;
@observable currentTemplate: TemplateRecord;
@observable currentTemplateIndex: number;
lightStore = new LightStore();
sealingStore = new SealingStore();
drillingStore = new DrillingStore();
@ -45,7 +45,7 @@ export class RightPanelStore implements IConfigStore
{
this.currentBoard = br;
if (this.currentBoard.Template)
this.currentTemplate = this.currentBoard.Template.Object as TemplateRecord;
this.currentTemplateIndex = this.currentBoard.Template.Index;
}
});
}

Loading…
Cancel
Save