Merge pull request 'Add behavior details panel & behavior object parameters are controlled' (#35) from dev-mrkbear into master
Reviewed-on: http://git.mrkbear.com/MrKBear/living-together/pulls/35
This commit is contained in:
		
						commit
						fdeced803b
					
				| @ -5,9 +5,10 @@ import { Brownian } from "./Brownian"; | |||||||
| import { BoundaryConstraint } from "./BoundaryConstraint";  | import { BoundaryConstraint } from "./BoundaryConstraint";  | ||||||
| 
 | 
 | ||||||
| const AllBehaviors: IAnyBehaviorRecorder[] = [ | const AllBehaviors: IAnyBehaviorRecorder[] = [ | ||||||
|  |     new BehaviorRecorder(Template), | ||||||
|     new BehaviorRecorder(Dynamics), |     new BehaviorRecorder(Dynamics), | ||||||
|     new BehaviorRecorder(Brownian), |     new BehaviorRecorder(Brownian), | ||||||
|     new BehaviorRecorder(BoundaryConstraint) |     new BehaviorRecorder(BoundaryConstraint), | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  | |||||||
| @ -26,8 +26,7 @@ class BoundaryConstraint extends Behavior<IBoundaryConstraintBehaviorParameter, | |||||||
| 	public override parameterOption = { | 	public override parameterOption = { | ||||||
| 		range: { | 		range: { | ||||||
| 			type: "LR", | 			type: "LR", | ||||||
| 			name: "$range", | 			name: "$range" | ||||||
| 			defaultValue: undefined |  | ||||||
| 		} | 		} | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| @ -43,15 +42,7 @@ class BoundaryConstraint extends Behavior<IBoundaryConstraintBehaviorParameter, | |||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     public effect(individual: Individual, group: Group, model: Model, t: number): void { |     public effect(individual: Individual, group: Group, model: Model, t: number): void { | ||||||
|         let rangeList: Range[] = []; |         let rangeList: Range[] = this.parameter.range.objects; | ||||||
| 		if (this.parameter.range instanceof Range) { |  | ||||||
| 			rangeList.push(this.parameter.range); |  | ||||||
| 		} |  | ||||||
| 		if (this.parameter.range instanceof Label) { |  | ||||||
| 			rangeList = model.getObjectByLabel(this.parameter.range).filter((obj) => { |  | ||||||
| 				return obj instanceof Range |  | ||||||
| 			}) as any; |  | ||||||
| 		} |  | ||||||
| 		for (let i = 0; i < rangeList.length; i++) { | 		for (let i = 0; i < rangeList.length; i++) { | ||||||
| 
 | 
 | ||||||
| 			let rx = rangeList[i].position[0] - individual.position[0]; | 			let rx = rangeList[i].position[0] - individual.position[0]; | ||||||
|  | |||||||
| @ -4,7 +4,14 @@ import { Individual } from "@Model/Individual"; | |||||||
| import { Model } from "@Model/Model"; | import { Model } from "@Model/Model"; | ||||||
| 
 | 
 | ||||||
| type ITemplateBehaviorParameter = { | type ITemplateBehaviorParameter = { | ||||||
|      |     testNumber: "number"; | ||||||
|  |     testString: "string"; | ||||||
|  |     testBoolean: "boolean"; | ||||||
|  |     testR: "R"; | ||||||
|  |     testG: "G"; | ||||||
|  |     testLR: "LR"; | ||||||
|  |     testLG: "LG"; | ||||||
|  |     testVec: "vec"; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type ITemplateBehaviorEvent = {} | type ITemplateBehaviorEvent = {} | ||||||
| @ -21,6 +28,53 @@ class Template extends Behavior<ITemplateBehaviorParameter, ITemplateBehaviorEve | |||||||
| 
 | 
 | ||||||
|     public override category: string = "$Category"; |     public override category: string = "$Category"; | ||||||
| 
 | 
 | ||||||
|  |     public override parameterOption = { | ||||||
|  |         testNumber: { | ||||||
|  |             name: "$Test", | ||||||
|  |             type: "number", | ||||||
|  |             defaultValue: 1, | ||||||
|  |             numberMax: 10, | ||||||
|  |             numberMin: 0, | ||||||
|  |             numberStep: 1 | ||||||
|  |         }, | ||||||
|  |         testString: { | ||||||
|  |             name: "$Test", | ||||||
|  |             type: "string", | ||||||
|  |             defaultValue: "default", | ||||||
|  |             maxLength: 12 | ||||||
|  |         }, | ||||||
|  |         testBoolean: { | ||||||
|  |             name: "$Test", | ||||||
|  |             type: "boolean", | ||||||
|  |             defaultValue: false, | ||||||
|  |             iconName: "Send" | ||||||
|  |         }, | ||||||
|  |         testR: { | ||||||
|  |             name: "$Test", | ||||||
|  |             type: "R" | ||||||
|  |         }, | ||||||
|  |         testG: { | ||||||
|  |             name: "$Test", | ||||||
|  |             type: "G" | ||||||
|  |         }, | ||||||
|  |         testLR: { | ||||||
|  |             name: "$Test", | ||||||
|  |             type: "LR" | ||||||
|  |         }, | ||||||
|  |         testLG: { | ||||||
|  |             name: "$Test", | ||||||
|  |             type: "LG" | ||||||
|  |         }, | ||||||
|  |         testVec: { | ||||||
|  |             name: "$Test", | ||||||
|  |             type: "vec", | ||||||
|  |             defaultValue: [1, 2, 3], | ||||||
|  |             numberMax: 10, | ||||||
|  |             numberMin: 0, | ||||||
|  |             numberStep: 1 | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|     public override terms: Record<string, Record<string, string>> = { |     public override terms: Record<string, Record<string, string>> = { | ||||||
|         "$Title": { |         "$Title": { | ||||||
|             "ZH_CN": "行为", |             "ZH_CN": "行为", | ||||||
| @ -29,6 +83,10 @@ class Template extends Behavior<ITemplateBehaviorParameter, ITemplateBehaviorEve | |||||||
|         "$Intro": { |         "$Intro": { | ||||||
|             "ZH_CN": "这是一个模板行为", |             "ZH_CN": "这是一个模板行为", | ||||||
|             "EN_US": "This is a template behavior" |             "EN_US": "This is a template behavior" | ||||||
|  |         }, | ||||||
|  |         "$Test": { | ||||||
|  |             "ZH_CN": "测试参数", | ||||||
|  |             "EN_US": "Test Parameter" | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -6,6 +6,7 @@ import "./TextField.scss"; | |||||||
| interface ITextFieldProps { | interface ITextFieldProps { | ||||||
|     className?: string; |     className?: string; | ||||||
|     keyI18n: AllI18nKeys; |     keyI18n: AllI18nKeys; | ||||||
|  |     keyI18nOption?: Record<string, string>; | ||||||
|     infoI18n?: AllI18nKeys; |     infoI18n?: AllI18nKeys; | ||||||
|     disableI18n?: AllI18nKeys; |     disableI18n?: AllI18nKeys; | ||||||
|     disableI18nOption?: Record<string, string>; |     disableI18nOption?: Record<string, string>; | ||||||
| @ -82,7 +83,7 @@ class TextField extends Component<ITextFieldProps> { | |||||||
|         return <> |         return <> | ||||||
|             <Theme className="text-field-root" fontLevel={FontLevel.normal}> |             <Theme className="text-field-root" fontLevel={FontLevel.normal}> | ||||||
|                 <div className="text-field-intro"> |                 <div className="text-field-intro"> | ||||||
|                     <Localization i18nKey={this.props.keyI18n}/> |                     <Localization i18nKey={this.props.keyI18n} options={this.props.keyI18nOption}/> | ||||||
|                 </div> |                 </div> | ||||||
|                 <div className="text-field-container"> |                 <div className="text-field-container"> | ||||||
|                     { |                     { | ||||||
|  | |||||||
| @ -136,6 +136,17 @@ class Status extends Emitter<IStatusEvent> { | |||||||
|         this.model.on("individualChange", () => { |         this.model.on("individualChange", () => { | ||||||
|             this.emit("individualChange"); |             this.emit("individualChange"); | ||||||
|         }); |         }); | ||||||
|  | 
 | ||||||
|  |         // 当模型中的标签和对象改变时,更新全部行为参数中的受控对象
 | ||||||
|  |         const updateBehaviorParameter = () => { | ||||||
|  |             this.model.updateBehaviorParameter(); | ||||||
|  |         } | ||||||
|  |         this.on("objectChange", updateBehaviorParameter); | ||||||
|  |         this.on("behaviorChange", updateBehaviorParameter); | ||||||
|  |         this.on("labelChange", updateBehaviorParameter); | ||||||
|  |         this.on("groupLabelChange", updateBehaviorParameter); | ||||||
|  |         this.on("rangeLabelChange", updateBehaviorParameter); | ||||||
|  |         this.on("behaviorAttrChange", updateBehaviorParameter); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public bindRenderer(renderer: AbstractRenderer) { |     public bindRenderer(renderer: AbstractRenderer) { | ||||||
| @ -198,15 +209,16 @@ class Status extends Emitter<IStatusEvent> { | |||||||
|      * 修改群属性 |      * 修改群属性 | ||||||
|      */ |      */ | ||||||
|     public changeBehaviorAttrib<K extends IBehaviorParameter, P extends keyof K | keyof Behavior<K>> |     public changeBehaviorAttrib<K extends IBehaviorParameter, P extends keyof K | keyof Behavior<K>> | ||||||
|     (id: ObjectID, key: P, val: IParamValue<K[P]>) { |     (id: ObjectID, key: P, val: IParamValue<K[P]>, noParameter?: boolean) { | ||||||
|         const behavior = this.model.getBehaviorById(id); |         const behavior = this.model.getBehaviorById(id); | ||||||
|         if (behavior) { |         if (behavior) { | ||||||
|             if (key === "color") { |             if (noParameter) { | ||||||
|                 behavior.color = val as number[]; |                 behavior[key as keyof Behavior<K>] = val as never; | ||||||
|             } else if (key === "name") { |  | ||||||
|                 behavior.name = val as string; |  | ||||||
|             } else { |             } else { | ||||||
|                 behavior.parameter[key] = val; |                 behavior.parameter[key] = val; | ||||||
|  |                 behavior.parameterOption[key]?.onChange ? | ||||||
|  |                     behavior.parameterOption[key]?.onChange!(val) : | ||||||
|  |                     undefined; | ||||||
|             } |             } | ||||||
|             this.emit("behaviorAttrChange"); |             this.emit("behaviorAttrChange"); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -113,5 +113,9 @@ const EN_US = { | |||||||
|     "Panel.Info.Label.List.Error.Nodata": "There are no labels in the model, click the button to create", |     "Panel.Info.Label.List.Error.Nodata": "There are no labels in the model, click the button to create", | ||||||
|     "Panel.Info.Behavior.Details.Error.Not.Behavior": "Please specify a behavior first to view the details", |     "Panel.Info.Behavior.Details.Error.Not.Behavior": "Please specify a behavior first to view the details", | ||||||
|     "Panel.Info.Behavior.Details.Behavior.Props": "{behavior} parameter", |     "Panel.Info.Behavior.Details.Behavior.Props": "{behavior} parameter", | ||||||
|  |     "Panel.Info.Behavior.Details.Parameter.Key": "{key}", | ||||||
|  |     "Panel.Info.Behavior.Details.Parameter.Key.Vec.X": "{key} X", | ||||||
|  |     "Panel.Info.Behavior.Details.Parameter.Key.Vec.Y": "{key} Y", | ||||||
|  |     "Panel.Info.Behavior.Details.Parameter.Key.Vec.Z": "{key} Z", | ||||||
| } | } | ||||||
| export default EN_US; | export default EN_US; | ||||||
| @ -113,5 +113,9 @@ const ZH_CN = { | |||||||
|     "Panel.Info.Label.List.Error.Nodata": "模型中没有标签,点击按钮以创建", |     "Panel.Info.Label.List.Error.Nodata": "模型中没有标签,点击按钮以创建", | ||||||
|     "Panel.Info.Behavior.Details.Error.Not.Behavior": "请先指定一个行为以查看详情", |     "Panel.Info.Behavior.Details.Error.Not.Behavior": "请先指定一个行为以查看详情", | ||||||
|     "Panel.Info.Behavior.Details.Behavior.Props": "{behavior}参数", |     "Panel.Info.Behavior.Details.Behavior.Props": "{behavior}参数", | ||||||
|  |     "Panel.Info.Behavior.Details.Parameter.Key": "{key}", | ||||||
|  |     "Panel.Info.Behavior.Details.Parameter.Key.Vec.X": "{key} X 坐标", | ||||||
|  |     "Panel.Info.Behavior.Details.Parameter.Key.Vec.Y": "{key} Y 坐标", | ||||||
|  |     "Panel.Info.Behavior.Details.Parameter.Key.Vec.Z": "{key} Z 坐标", | ||||||
| } | } | ||||||
| export default ZH_CN; | export default ZH_CN; | ||||||
| @ -24,7 +24,7 @@ type IMapObjectParamTypeKeyToType = { | |||||||
|     "R": IObjectParamCacheType<Range | undefined>; |     "R": IObjectParamCacheType<Range | undefined>; | ||||||
|     "G": IObjectParamCacheType<Group | undefined>; |     "G": IObjectParamCacheType<Group | undefined>; | ||||||
|     "LR": IObjectParamCacheType<Label | Range | undefined, Range[]>; |     "LR": IObjectParamCacheType<Label | Range | undefined, Range[]>; | ||||||
|     "LG": IObjectParamCacheType<Label | Group | undefined, Range[]>; |     "LG": IObjectParamCacheType<Label | Group | undefined, Group[]>; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type IMapVectorParamTypeKeyToType = { | type IMapVectorParamTypeKeyToType = { | ||||||
| @ -87,7 +87,7 @@ interface IBehaviorParameterOptionItem<T extends IParamType = IParamType> { | |||||||
|     /** |     /** | ||||||
|      * 字符长度 |      * 字符长度 | ||||||
|      */ |      */ | ||||||
|     stringLength?: number; |     maxLength?: number; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * 数字步长 |      * 数字步长 | ||||||
| @ -417,6 +417,7 @@ type IRenderBehavior = BehaviorInfo | Behavior; | |||||||
| 
 | 
 | ||||||
| export { | export { | ||||||
|     Behavior, BehaviorRecorder, IBehaviorParameterOption, IBehaviorParameterOptionItem, IParamValue, |     Behavior, BehaviorRecorder, IBehaviorParameterOption, IBehaviorParameterOptionItem, IParamValue, | ||||||
|     IAnyBehavior, IAnyBehaviorRecorder, BehaviorInfo, IRenderBehavior, IBehaviorParameter |     IAnyBehavior, IAnyBehaviorRecorder, BehaviorInfo, IRenderBehavior, IBehaviorParameter, | ||||||
|  |     isObjectType, isVectorType | ||||||
| }; | }; | ||||||
| export default { Behavior }; | export default { Behavior }; | ||||||
| @ -5,7 +5,7 @@ import { Emitter, EventType, EventMixin } from "./Emitter"; | |||||||
| import { CtrlObject } from "./CtrlObject"; | import { CtrlObject } from "./CtrlObject"; | ||||||
| import { ObjectID, AbstractRenderer } from "./Renderer"; | import { ObjectID, AbstractRenderer } from "./Renderer"; | ||||||
| import { Label } from "./Label"; | import { Label } from "./Label"; | ||||||
| import { Behavior, IAnyBehavior, IAnyBehaviorRecorder } from "./Behavior"; | import { Behavior, IAnyBehavior, IAnyBehaviorRecorder, IParamValue } from "./Behavior"; | ||||||
| 
 | 
 | ||||||
| type ModelEvent = { | type ModelEvent = { | ||||||
|     labelChange: Label[]; |     labelChange: Label[]; | ||||||
| @ -206,6 +206,68 @@ class Model extends Emitter<ModelEvent> { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * 更新全部行为的参数 | ||||||
|  |      */ | ||||||
|  |     public updateBehaviorParameter() { | ||||||
|  |         for (let i = 0; i < this.behaviorPool.length; i++) { | ||||||
|  |             const behavior = this.behaviorPool[i]; | ||||||
|  |              | ||||||
|  |             for (let key in behavior.parameterOption) { | ||||||
|  |                 switch (behavior.parameterOption[key].type) { | ||||||
|  | 
 | ||||||
|  |                     case "R": | ||||||
|  |                         const dataR: IParamValue<"R"> = behavior.parameter[key]; | ||||||
|  |                         dataR.objects = undefined; | ||||||
|  |                          | ||||||
|  |                         if (dataR.picker instanceof Range && !dataR.picker.isDeleted()) { | ||||||
|  |                             dataR.objects = dataR.picker; | ||||||
|  |                         } | ||||||
|  |                         break; | ||||||
|  | 
 | ||||||
|  |                     case "G": | ||||||
|  |                         const dataG: IParamValue<"G"> = behavior.parameter[key]; | ||||||
|  |                         dataG.objects = undefined; | ||||||
|  |                          | ||||||
|  |                         if (dataG.picker instanceof Group && !dataG.picker.isDeleted()) { | ||||||
|  |                             dataG.objects = dataG.picker; | ||||||
|  |                         } | ||||||
|  |                         break; | ||||||
|  | 
 | ||||||
|  |                     case "LR": | ||||||
|  |                         const dataLR: IParamValue<"LR"> = behavior.parameter[key]; | ||||||
|  |                         dataLR.objects = []; | ||||||
|  | 
 | ||||||
|  |                         if (dataLR.picker instanceof Range && !dataLR.picker.isDeleted()) { | ||||||
|  |                             dataLR.objects.push(dataLR.picker); | ||||||
|  |                         } | ||||||
|  | 
 | ||||||
|  |                         if (dataLR.picker instanceof Label && !dataLR.picker.isDeleted()) { | ||||||
|  |                             dataLR.objects = this.getObjectByLabel(dataLR.picker).filter((obj) => { | ||||||
|  |                                 return obj instanceof Range; | ||||||
|  |                             }) as any; | ||||||
|  |                         } | ||||||
|  |                         break; | ||||||
|  | 
 | ||||||
|  |                     case "LG": | ||||||
|  |                         const dataLG: IParamValue<"LG"> = behavior.parameter[key]; | ||||||
|  |                         dataLG.objects = []; | ||||||
|  | 
 | ||||||
|  |                         if (dataLG.picker instanceof Group && !dataLG.picker.isDeleted()) { | ||||||
|  |                             dataLG.objects.push(dataLG.picker); | ||||||
|  |                         } | ||||||
|  | 
 | ||||||
|  |                         if (dataLG.picker instanceof Label && !dataLG.picker.isDeleted()) { | ||||||
|  |                             dataLG.objects = this.getObjectByLabel(dataLG.picker).filter((obj) => { | ||||||
|  |                                 return obj instanceof Group; | ||||||
|  |                             }) as any; | ||||||
|  |                         } | ||||||
|  |                         break; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * 搜索并删除一个 Behavior |      * 搜索并删除一个 Behavior | ||||||
|      * @param name 搜索值 |      * @param name 搜索值 | ||||||
|  | |||||||
| @ -55,13 +55,16 @@ class SimulatorWeb extends Component { | |||||||
|             this.status.model.update(0); |             this.status.model.update(0); | ||||||
|             this.status.newLabel().name = "New Label"; |             this.status.newLabel().name = "New Label"; | ||||||
|             this.status.newLabel().name = "Test Label 01"; |             this.status.newLabel().name = "Test Label 01"; | ||||||
|             let dynamic = this.status.model.addBehavior(AllBehaviors[0]); |             let template = this.status.model.addBehavior(AllBehaviors[0]); | ||||||
|  |             template.name = "Template"; template.color = [150, 20, 220]; | ||||||
|  |             let dynamic = this.status.model.addBehavior(AllBehaviors[1]); | ||||||
|             dynamic.name = "Dynamic"; dynamic.color = [250, 200, 80]; |             dynamic.name = "Dynamic"; dynamic.color = [250, 200, 80]; | ||||||
|             let brownian = this.status.model.addBehavior(AllBehaviors[1]); |             let brownian = this.status.model.addBehavior(AllBehaviors[2]); | ||||||
|             brownian.name = "Brownian"; brownian.color = [200, 80, 250]; |             brownian.name = "Brownian"; brownian.color = [200, 80, 250]; | ||||||
|             let boundary = this.status.model.addBehavior(AllBehaviors[2]); |             let boundary = this.status.model.addBehavior(AllBehaviors[3]); | ||||||
|             boundary.name = "Boundary"; boundary.color = [80, 200, 250]; |             boundary.name = "Boundary"; boundary.color = [80, 200, 250]; | ||||||
|             boundary.parameter.range = this.status.model.allRangeLabel; |             // boundary.parameter.range = this.status.model.allRangeLabel;
 | ||||||
|  |             group.addBehavior(template); | ||||||
|             group.addBehavior(dynamic); |             group.addBehavior(dynamic); | ||||||
|             group.addBehavior(brownian); |             group.addBehavior(brownian); | ||||||
|             group.addBehavior(boundary); |             group.addBehavior(boundary); | ||||||
|  | |||||||
| @ -1,19 +1,26 @@ | |||||||
| import { Component, ReactNode} from "react"; | import { Component, Fragment, ReactNode} from "react"; | ||||||
|  | import { useSettingWithEvent, IMixinSettingProps } from "@Context/Setting"; | ||||||
| import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status"; | import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status"; | ||||||
| import { Behavior } from "@Model/Behavior"; | import { Behavior, IBehaviorParameter, isObjectType, isVectorType } from "@Model/Behavior"; | ||||||
| import { Message } from "@Component/Message/Message"; | import { Message } from "@Component/Message/Message"; | ||||||
| import { AttrInput } from "@Component/AttrInput/AttrInput"; | import { AttrInput } from "@Component/AttrInput/AttrInput"; | ||||||
| import { ColorInput } from "@Component/ColorInput/ColorInput"; | import { ColorInput } from "@Component/ColorInput/ColorInput"; | ||||||
| import { TogglesInput } from "@Component/TogglesInput/TogglesInput"; | import { TogglesInput } from "@Component/TogglesInput/TogglesInput"; | ||||||
| import { ConfirmPopup } from "@Component/ConfirmPopup/ConfirmPopup"; | import { ConfirmPopup } from "@Component/ConfirmPopup/ConfirmPopup"; | ||||||
|  | import { ObjectPicker } from "@Component/ObjectPicker/ObjectPicker"; | ||||||
| import "./BehaviorDetails.scss"; | import "./BehaviorDetails.scss"; | ||||||
| 
 | 
 | ||||||
| interface IBehaviorDetailsProps {} | interface IBehaviorDetailsProps {} | ||||||
| 
 | 
 | ||||||
|  | @useSettingWithEvent("language") | ||||||
| @useStatusWithEvent("focusBehaviorChange", "behaviorAttrChange") | @useStatusWithEvent("focusBehaviorChange", "behaviorAttrChange") | ||||||
| class BehaviorDetails extends Component<IBehaviorDetailsProps & IMixinStatusProps> { | class BehaviorDetails extends Component<IBehaviorDetailsProps & IMixinStatusProps & IMixinSettingProps> { | ||||||
|  | 
 | ||||||
|  | 	private renderFrom<T extends IBehaviorParameter> | ||||||
|  |     (behavior: Behavior<T, Record<string, any>>): ReactNode { | ||||||
|  | 
 | ||||||
|  |         const allParameterKeys = Object.getOwnPropertyNames(behavior.parameterOption); | ||||||
| 
 | 
 | ||||||
| 	private renderFrom(behavior: Behavior): ReactNode { |  | ||||||
| 		return <> | 		return <> | ||||||
|          |          | ||||||
|             <Message i18nKey="Common.Attr.Title.Basic" isTitle first/> |             <Message i18nKey="Common.Attr.Title.Basic" isTitle first/> | ||||||
| @ -21,7 +28,7 @@ class BehaviorDetails extends Component<IBehaviorDetailsProps & IMixinStatusProp | |||||||
|             <AttrInput |             <AttrInput | ||||||
|                 id={behavior.id} keyI18n="Common.Attr.Key.Display.Name" value={behavior.name} |                 id={behavior.id} keyI18n="Common.Attr.Key.Display.Name" value={behavior.name} | ||||||
|                 valueChange={(val) => { |                 valueChange={(val) => { | ||||||
|                     this.props.status?.changeBehaviorAttrib(behavior.id, "name", val); |                     this.props.status?.changeBehaviorAttrib(behavior.id, "name", val, true); | ||||||
|                 }} |                 }} | ||||||
|             /> |             /> | ||||||
| 
 | 
 | ||||||
| @ -29,7 +36,7 @@ class BehaviorDetails extends Component<IBehaviorDetailsProps & IMixinStatusProp | |||||||
|                 keyI18n="Common.Attr.Key.Color" |                 keyI18n="Common.Attr.Key.Color" | ||||||
|                 value={behavior.color} |                 value={behavior.color} | ||||||
|                 valueChange={(color) => { |                 valueChange={(color) => { | ||||||
|                     this.props.status?.changeBehaviorAttrib(behavior.id, "color", color); |                     this.props.status?.changeBehaviorAttrib(behavior.id, "color", color, true); | ||||||
|                 }} |                 }} | ||||||
|             /> |             /> | ||||||
| 
 | 
 | ||||||
| @ -53,22 +60,132 @@ class BehaviorDetails extends Component<IBehaviorDetailsProps & IMixinStatusProp | |||||||
| 				}} | 				}} | ||||||
| 			/> | 			/> | ||||||
| 
 | 
 | ||||||
|  |             { | ||||||
|  |                 allParameterKeys.length > 0 ? | ||||||
|                     <Message |                     <Message | ||||||
|                         isTitle |                         isTitle | ||||||
|                         i18nKey="Panel.Info.Behavior.Details.Behavior.Props" |                         i18nKey="Panel.Info.Behavior.Details.Behavior.Props" | ||||||
|                         options={{ |                         options={{ | ||||||
|                     behavior: behavior.getTerms(behavior.behaviorName) |                             behavior: behavior.getTerms(behavior.behaviorName, this.props.setting?.language) | ||||||
|                         }} |                         }} | ||||||
|             /> |                     /> : null | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             { | ||||||
|  |                 allParameterKeys.map((key) => { | ||||||
|  |                     return this.renderParameter(behavior, key); | ||||||
|  |                 }) | ||||||
|  |             } | ||||||
| 
 | 
 | ||||||
|         </>; |         </>; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	public render(): ReactNode { |     private renderParameter<T extends IBehaviorParameter> | ||||||
| 		if (this.props.status) { |     (behavior: Behavior<T, Record<string, any>>, key: keyof T): ReactNode { | ||||||
|             if (this.props.status.focusBehavior) { |         const type = behavior.parameterOption[key]; | ||||||
|                 return this.renderFrom(this.props.status.focusBehavior); |         const value = behavior.parameter[key]; | ||||||
|  |         const indexKey = `${behavior.id}-${key}`; | ||||||
|  | 
 | ||||||
|  |         if (type.type === "number") { | ||||||
|  |             return <AttrInput | ||||||
|  |                 keyI18n="Panel.Info.Behavior.Details.Parameter.Key" | ||||||
|  |                 keyI18nOption={{ key: behavior.getTerms(type.name, this.props.setting?.language) }} | ||||||
|  |                 key={indexKey} id={indexKey} isNumber={true} step={type.numberStep} maxLength={type.maxLength} | ||||||
|  |                 max={type.numberMax} min={type.numberMin} | ||||||
|  |                 value={(value as number) ?? 0} | ||||||
|  |                 valueChange={(val) => { | ||||||
|  |                     this.props.status?.changeBehaviorAttrib(behavior.id, key as string, (val as any) / 1); | ||||||
|  |                 }} | ||||||
|  |             /> | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         if (type.type === "string") { | ||||||
|  |             return <AttrInput | ||||||
|  |                 keyI18n="Panel.Info.Behavior.Details.Parameter.Key" | ||||||
|  |                 keyI18nOption={{ key: behavior.getTerms(type.name, this.props.setting?.language) }} | ||||||
|  |                 key={indexKey} id={indexKey} maxLength={type.maxLength} | ||||||
|  |                 value={(value as string) ?? ""} | ||||||
|  |                 valueChange={(val) => { | ||||||
|  |                     this.props.status?.changeBehaviorAttrib(behavior.id, key as string, val); | ||||||
|  |                 }} | ||||||
|  |             /> | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (type.type === "boolean") { | ||||||
|  |             return <TogglesInput | ||||||
|  |                 keyI18n="Panel.Info.Behavior.Details.Parameter.Key" | ||||||
|  |                 keyI18nOption={{ key: behavior.getTerms(type.name, this.props.setting?.language) }} | ||||||
|  | 				onIconName={type.iconName} key={indexKey} value={(value as boolean) ?? false} | ||||||
|  | 				valueChange={(val) => { | ||||||
|  | 					this.props.status?.changeBehaviorAttrib(behavior.id, key as string, val); | ||||||
|  | 				}} | ||||||
|  | 			/> | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (isObjectType(type.type as any)) { | ||||||
|  |             return <ObjectPicker | ||||||
|  |                 keyI18n="Panel.Info.Behavior.Details.Parameter.Key" | ||||||
|  |                 keyI18nOption={{ key: behavior.getTerms(type.name, this.props.setting?.language) }} | ||||||
|  |                 type={type.type} value={(value as any).picker} | ||||||
|  |                 valueChange={(obj) => { | ||||||
|  |                     (value as any).picker = obj; | ||||||
|  |                     this.props.status?.changeBehaviorAttrib(behavior.id, key as string, value); | ||||||
|  |                 }} | ||||||
|  |                 cleanValue={() => { | ||||||
|  |                     (value as any).picker = undefined; | ||||||
|  |                     this.props.status?.changeBehaviorAttrib(behavior.id, key as string, value); | ||||||
|  |                 }} | ||||||
|  |             /> | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (isVectorType(type.type as any)) { | ||||||
|  |             return <Fragment key={indexKey}> | ||||||
|  |                  | ||||||
|  |                 <AttrInput | ||||||
|  |                     keyI18n="Panel.Info.Behavior.Details.Parameter.Key.Vec.X" | ||||||
|  |                     keyI18nOption={{ key: behavior.getTerms(type.name, this.props.setting?.language) }} | ||||||
|  |                     key={`${indexKey}-X`} id={indexKey} isNumber={true} step={type.numberStep} maxLength={type.maxLength} | ||||||
|  |                     max={type.numberMax} min={type.numberMin} | ||||||
|  |                     value={(value as number[])[0] ?? 0} | ||||||
|  |                     valueChange={(val) => { | ||||||
|  |                         (value as number[])[0] = (val as any) / 1; | ||||||
|  |                         this.props.status?.changeBehaviorAttrib(behavior.id, key as string, value); | ||||||
|  |                     }} | ||||||
|  |                 /> | ||||||
|  | 
 | ||||||
|  |                 <AttrInput | ||||||
|  |                     keyI18n="Panel.Info.Behavior.Details.Parameter.Key.Vec.Y" | ||||||
|  |                     keyI18nOption={{ key: behavior.getTerms(type.name, this.props.setting?.language) }} | ||||||
|  |                     key={`${indexKey}-Y`} id={indexKey} isNumber={true} step={type.numberStep} maxLength={type.maxLength} | ||||||
|  |                     max={type.numberMax} min={type.numberMin} | ||||||
|  |                     value={(value as number[])[1] ?? 0} | ||||||
|  |                     valueChange={(val) => { | ||||||
|  |                         (value as number[])[1] = (val as any) / 1; | ||||||
|  |                         this.props.status?.changeBehaviorAttrib(behavior.id, key as string, value); | ||||||
|  |                     }} | ||||||
|  |                 /> | ||||||
|  | 
 | ||||||
|  |                 <AttrInput | ||||||
|  |                     keyI18n="Panel.Info.Behavior.Details.Parameter.Key.Vec.Z" | ||||||
|  |                     keyI18nOption={{ key: behavior.getTerms(type.name, this.props.setting?.language) }} | ||||||
|  |                     key={`${indexKey}-Z`} id={indexKey} isNumber={true} step={type.numberStep} maxLength={type.maxLength} | ||||||
|  |                     max={type.numberMax} min={type.numberMin} | ||||||
|  |                     value={(value as number[])[2] ?? 0} | ||||||
|  |                     valueChange={(val) => { | ||||||
|  |                         (value as number[])[2] = (val as any) / 1; | ||||||
|  |                         this.props.status?.changeBehaviorAttrib(behavior.id, key as string, value); | ||||||
|  |                     }} | ||||||
|  |                 /> | ||||||
|  | 
 | ||||||
|  |             </Fragment> | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return <Fragment key={indexKey}/> | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 	public render(): ReactNode { | ||||||
|  | 		if (this.props.status && this.props.status.focusBehavior) { | ||||||
|  |             return this.renderFrom(this.props.status.focusBehavior); | ||||||
|         } |         } | ||||||
| 		return <Message i18nKey="Panel.Info.Behavior.Details.Error.Not.Behavior"/>; | 		return <Message i18nKey="Panel.Info.Behavior.Details.Error.Not.Behavior"/>; | ||||||
| 	} | 	} | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user