Compare commits
	
		
			5 Commits
		
	
	
		
			51f11866a3
			...
			06e68d31c5
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 06e68d31c5 | |||
| b420b3956f | |||
| 27927ddde8 | |||
| a6268bf24d | |||
| ff27bddf27 | 
| @ -11,6 +11,7 @@ div.attr-input { | ||||
| 	div.input-intro { | ||||
| 		width: 50%; | ||||
| 		height: 100%; | ||||
|         min-height: $line-min-height; | ||||
| 		max-width: 220px; | ||||
| 		display: flex; | ||||
| 		align-items: center; | ||||
|  | ||||
| @ -12,6 +12,7 @@ div.color-input-root { | ||||
| 		width: 50%; | ||||
| 		height: 100%; | ||||
| 		max-width: 220px; | ||||
|         min-height: $line-min-height; | ||||
| 		display: flex; | ||||
| 		align-items: center; | ||||
|         padding-right: 5px; | ||||
|  | ||||
| @ -1,3 +0,0 @@ | ||||
| div.panel-error-message { | ||||
|     padding-top: 5px; | ||||
| } | ||||
| @ -1,17 +0,0 @@ | ||||
| import { AllI18nKeys, Localization } from "@Component/Localization/Localization"; | ||||
| import { FunctionComponent } from "react"; | ||||
| import "./ErrorMessage.scss"; | ||||
| 
 | ||||
| interface IErrorMessageProps { | ||||
|     i18nKey: AllI18nKeys; | ||||
|     options?: Record<string, string>; | ||||
|     className?: string; | ||||
| } | ||||
| 
 | ||||
| const ErrorMessage: FunctionComponent<IErrorMessageProps> = (props) => { | ||||
|     return <div className={["panel-error-message", props.className].filter(c => !!c).join(" ")}> | ||||
|         <Localization i18nKey={props.i18nKey} options={props.options}/> | ||||
|     </div> | ||||
| } | ||||
| 
 | ||||
| export { ErrorMessage }; | ||||
| @ -2,7 +2,6 @@ import { Component, RefObject } from "react"; | ||||
| import { Label } from "@Model/Label"; | ||||
| import { Icon } from "@fluentui/react"; | ||||
| import { useSetting, IMixinSettingProps, Themes } from "@Context/Setting"; | ||||
| import { ErrorMessage } from "@Component/ErrorMessage/ErrorMessage"; | ||||
| import "./LabelList.scss"; | ||||
| 
 | ||||
| interface ILabelListProps { | ||||
|  | ||||
| @ -12,6 +12,7 @@ div.label-picker-root { | ||||
|     div.input-intro { | ||||
| 		width: 50%; | ||||
| 		height: 100%; | ||||
| 		min-height: $line-min-height; | ||||
| 		max-width: 220px; | ||||
| 		display: flex; | ||||
| 		align-items: center; | ||||
|  | ||||
							
								
								
									
										20
									
								
								source/Component/Message/Message.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								source/Component/Message/Message.scss
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | ||||
| div.panel-error-message { | ||||
|     transition: none !important; | ||||
|     padding-top: 5px; | ||||
|     padding-bottom: 5px; | ||||
|     min-height: 26px; | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
| 
 | ||||
|     span { | ||||
|         display: block; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| div.panel-error-message.title { | ||||
|     padding: 15px 0 5px 0; | ||||
| } | ||||
| 
 | ||||
| div.panel-error-message.title.first { | ||||
|     padding: 5px 0 5px 0; | ||||
| } | ||||
							
								
								
									
										42
									
								
								source/Component/Message/Message.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								source/Component/Message/Message.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | ||||
| import { AllI18nKeys, I18N } from "@Component/Localization/Localization"; | ||||
| import { useSetting, IMixinSettingProps, Themes, Language } from "@Context/Setting"; | ||||
| import { FunctionComponent } from "react"; | ||||
| import "./Message.scss"; | ||||
| 
 | ||||
| interface IMessageProps { | ||||
|     i18nKey: AllI18nKeys; | ||||
|     options?: Record<string, string>; | ||||
|     className?: string; | ||||
|     isTitle?: boolean; | ||||
|     first?: boolean; | ||||
| } | ||||
| 
 | ||||
| const MessageView: FunctionComponent<IMessageProps & IMixinSettingProps> = (props) => { | ||||
| 
 | ||||
|     let theme = props.setting ? props.setting.themes : Themes.dark; | ||||
|     let language: Language = props.setting ? props.setting.language : "EN_US"; | ||||
|     let classList: string[] = [ | ||||
|         "panel-error-message", | ||||
|         theme === Themes.dark ? "dark" : "light", | ||||
|     ]; | ||||
| 
 | ||||
|     if (props.first) { | ||||
|         classList.push("first"); | ||||
|     } | ||||
| 
 | ||||
|     if (props.isTitle) { | ||||
|         classList.push("title"); | ||||
|         classList.push("font-lvl3"); | ||||
|     } | ||||
| 
 | ||||
|     if (props.className) { | ||||
|         classList.push(props.className); | ||||
|     } | ||||
| 
 | ||||
|     return <div className={classList.join(" ")}> | ||||
|         <span className={language}>{I18N(language, props.i18nKey, props.options)}</span> | ||||
|     </div> | ||||
| } | ||||
| 
 | ||||
| const Message = useSetting(MessageView); | ||||
| export { Message }; | ||||
| @ -1,5 +1,6 @@ | ||||
| div.picker-list-root { | ||||
| 	max-width: 200px; | ||||
| 	height: 100%; | ||||
| 	padding: 0px; | ||||
| 	margin: 0px; | ||||
| 	overflow-y: auto; | ||||
| @ -45,7 +46,7 @@ div.picker-list-root { | ||||
| 
 | ||||
| 	span.picker-list-nodata { | ||||
| 		display: inline-block; | ||||
| 		padding: 5px; | ||||
| 		padding: 8px; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -62,7 +63,7 @@ div.picker-list-root::-webkit-scrollbar { | ||||
| div.picker-list-root::-webkit-scrollbar-thumb { | ||||
| 	/*滚动条里面小方块*/ | ||||
| 	border-radius: 8px; | ||||
| 	background-color: rgba($color: #000000, $alpha: .1); | ||||
| 	background-color: rgba($color: #000000, $alpha: .2); | ||||
| } | ||||
| 
 | ||||
| div.picker-list-root::-webkit-scrollbar-track { | ||||
|  | ||||
| @ -12,6 +12,7 @@ div.toggles-input { | ||||
| 		width: 50%; | ||||
| 		height: 100%; | ||||
| 		max-width: 220px; | ||||
|         min-height: $line-min-height; | ||||
| 		display: flex; | ||||
| 		align-items: center; | ||||
|         padding-right: 5px; | ||||
|  | ||||
| @ -3,6 +3,7 @@ import { Emitter } from "@Model/Emitter"; | ||||
| import { Model, ObjectID } from "@Model/Model"; | ||||
| import { Label } from "@Model/Label"; | ||||
| import { Range } from "@Model/Range"; | ||||
| import { Group } from "@Model/Group"; | ||||
| import { Archive } from "@Model/Archive"; | ||||
| import { AbstractRenderer } from "@Model/Renderer"; | ||||
| import { ClassicRenderer, MouseMod } from "@GLRender/ClassicRenderer"; | ||||
| @ -31,9 +32,11 @@ interface IStatusEvent { | ||||
|     focusLabelChange: void; | ||||
|     objectChange: void; | ||||
|     rangeLabelChange: void; | ||||
|     groupLabelChange: void; | ||||
|     labelChange: void; | ||||
|     rangeAttrChange: void; | ||||
|     labelAttrChange: void; | ||||
|     groupAttrChange: void; | ||||
| } | ||||
| 
 | ||||
| class Status extends Emitter<IStatusEvent> { | ||||
| @ -83,7 +86,9 @@ class Status extends Emitter<IStatusEvent> { | ||||
| 
 | ||||
|         // 对象变换时执行渲染,更新渲染器数据
 | ||||
|         this.on("objectChange", () => { | ||||
|             this.model.draw(); | ||||
|             setTimeout(() => { | ||||
|                 this.model.draw(); | ||||
|             }); | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
| @ -122,6 +127,35 @@ class Status extends Emitter<IStatusEvent> { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 修改群属性 | ||||
|      */ | ||||
|     public changeGroupAttrib<K extends keyof Group> | ||||
|     (id: ObjectID, key: K, val: Group[K]) { | ||||
|         const group = this.model.getObjectById(id); | ||||
|         if (group && group instanceof Group) { | ||||
|             group[key] = val; | ||||
|             this.emit("groupAttrChange"); | ||||
|             this.model.draw(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public addGroupLabel(id: ObjectID, val: Label) { | ||||
|         const group = this.model.getObjectById(id); | ||||
|         if (group && group instanceof Group) { | ||||
|             group.addLabel(val); | ||||
|             this.emit("groupLabelChange"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public deleteGroupLabel(id: ObjectID, val: Label) { | ||||
|         const group = this.model.getObjectById(id); | ||||
|         if (group && group instanceof Group) { | ||||
|             group.removeLabel(val); | ||||
|             this.emit("groupLabelChange"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public addRangeLabel(id: ObjectID, val: Label) { | ||||
|         const range = this.model.getObjectById(id); | ||||
|         if (range && range instanceof Range) { | ||||
|  | ||||
| @ -34,12 +34,17 @@ const EN_US = { | ||||
|     "Panel.Info.Render.View": "Live simulation results preview", | ||||
|     "Panel.Title.Object.List.View": "Object list", | ||||
|     "Panel.Info.Object.List.View": "Edit view all Object Properties", | ||||
|     "Panel.Title.Range.Details.View": "Range attributes", | ||||
|     "Panel.Title.Range.Details.View": "Range", | ||||
|     "Panel.Info.Range.Details.View": "Edit view range attributes", | ||||
|     "Panel.Title.Label.List.View": "Label list", | ||||
|     "Panel.Info.Label.List.View": "Edit view label list", | ||||
|     "Panel.Title.Label.Details.View": "Label attributes", | ||||
|     "Panel.Title.Label.Details.View": "Label", | ||||
|     "Panel.Info.Label.Details.View": "Edit view label attributes", | ||||
|     "Panel.Title.Group.Details.View": "Group", | ||||
|     "Panel.Info.Group.Details.View": "Edit view group attributes", | ||||
|     "Common.Attr.Title.Basic": "Basic properties", | ||||
|     "Common.Attr.Title.Spatial": "Spatial property", | ||||
|     "Common.Attr.Title.Individual.Generation": "Individual generation", | ||||
|     "Common.Attr.Key.Display.Name": "Display name", | ||||
|     "Common.Attr.Key.Position.X": "Position X", | ||||
|     "Common.Attr.Key.Position.Y": "Position Y", | ||||
| @ -54,8 +59,11 @@ const EN_US = { | ||||
|     "Common.Attr.Key.Label": "Label", | ||||
|     "Common.Attr.Key.Error.Multiple": "Multiple values", | ||||
|     "Common.Attr.Key.Label.Picker.Nodata": "No tags can be added", | ||||
|     "Common.Attr.Key.Generation": "Generation", | ||||
|     "Panel.Info.Range.Details.Attr.Error.Not.Range": "Object is not a Range", | ||||
|     "Panel.Info.Range.Details.Attr.Error.Unspecified": "Unspecified range object", | ||||
|     "Panel.Info.Group.Details.Attr.Error.Not.Group": "Object is not a Group", | ||||
|     "Panel.Info.Group.Details.Attr.Error.Unspecified": "Unspecified group object", | ||||
|     "Panel.Info.Label.Details.Error.Unspecified": "Label object not specified", | ||||
|     "Panel.Info.Label.List.Error.Nodata": "There are no labels in the model, click the button to create", | ||||
| } | ||||
|  | ||||
| @ -34,12 +34,17 @@ const ZH_CN = { | ||||
|     "Panel.Info.Render.View": "实时仿真结果预览", | ||||
|     "Panel.Title.Object.List.View": "对象列表", | ||||
|     "Panel.Info.Object.List.View": "编辑查看全部对象列表", | ||||
|     "Panel.Title.Range.Details.View": "范围属性", | ||||
|     "Panel.Title.Range.Details.View": "范围", | ||||
|     "Panel.Info.Range.Details.View": "编辑查看范围属性", | ||||
|     "Panel.Title.Label.List.View": "标签列表", | ||||
|     "Panel.Info.Label.List.View": "编辑查看标签列表", | ||||
|     "Panel.Title.Label.Details.View": "标签属性", | ||||
|     "Panel.Title.Label.Details.View": "标签", | ||||
|     "Panel.Info.Label.Details.View": "编辑查看标签属性", | ||||
|     "Panel.Title.Group.Details.View": "群", | ||||
|     "Panel.Info.Group.Details.View": "编辑查看群属性", | ||||
|     "Common.Attr.Title.Basic": "基础属性", | ||||
|     "Common.Attr.Title.Spatial": "空间属性", | ||||
|     "Common.Attr.Title.Individual.Generation": "个体生成", | ||||
|     "Common.Attr.Key.Display.Name": "显示名称", | ||||
|     "Common.Attr.Key.Position.X": "X 坐标", | ||||
|     "Common.Attr.Key.Position.Y": "Y 坐标", | ||||
| @ -54,8 +59,11 @@ const ZH_CN = { | ||||
|     "Common.Attr.Key.Label": "标签", | ||||
|     "Common.Attr.Key.Error.Multiple": "多重数值", | ||||
|     "Common.Attr.Key.Label.Picker.Nodata": "没有可以被添加的标签", | ||||
|     "Common.Attr.Key.Generation": "生成", | ||||
|     "Panel.Info.Range.Details.Attr.Error.Not.Range": "对象不是一个范围", | ||||
|     "Panel.Info.Range.Details.Attr.Error.Unspecified": "未指定范围对象", | ||||
|     "Panel.Info.Group.Details.Attr.Error.Not.Group": "对象不是一个群", | ||||
|     "Panel.Info.Group.Details.Attr.Error.Unspecified": "未指定群对象", | ||||
|     "Panel.Info.Label.Details.Error.Unspecified": "未指定标签对象", | ||||
|     "Panel.Info.Label.List.Error.Nodata": "模型中没有标签,点击按钮以创建", | ||||
| } | ||||
|  | ||||
| @ -77,7 +77,7 @@ class SimulatorWeb extends Component { | ||||
|                     items: [{ | ||||
|                         panels: ["ObjectList", "Test tab"] | ||||
|                     }, { | ||||
|                         panels: ["RangeDetails", "LabelDetails"] | ||||
|                         panels: ["GroupDetails", "RangeDetails", "LabelDetails"] | ||||
|                     }], | ||||
|                     layout: LayoutDirection.Y | ||||
|                 } | ||||
|  | ||||
							
								
								
									
										0
									
								
								source/Panel/GroupDetails/GroupDetails.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								source/Panel/GroupDetails/GroupDetails.scss
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										133
									
								
								source/Panel/GroupDetails/GroupDetails.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								source/Panel/GroupDetails/GroupDetails.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,133 @@ | ||||
| import { Component, ReactNode } from "react"; | ||||
| import { AttrInput } from "@Component/AttrInput/AttrInput"; | ||||
| import { useStatusWithEvent, IMixinStatusProps, Status } from "@Context/Status"; | ||||
| import { Message } from "@Component/Message/Message"; | ||||
| import { ObjectID } from "@Model/Renderer"; | ||||
| import { ColorInput } from "@Component/ColorInput/ColorInput"; | ||||
| import { TogglesInput } from "@Component/TogglesInput/TogglesInput"; | ||||
| import { LabelPicker } from "@Component/LabelPicker/LabelPicker"; | ||||
| import { Group } from "@Model/Group"; | ||||
| import { AllI18nKeys } from "@Component/Localization/Localization"; | ||||
| import "./GroupDetails.scss"; | ||||
| 
 | ||||
| interface IGroupDetailsProps {} | ||||
| 
 | ||||
| @useStatusWithEvent("groupAttrChange", "groupLabelChange", "focusObjectChange") | ||||
| class GroupDetails extends Component<IGroupDetailsProps & IMixinStatusProps> { | ||||
| 
 | ||||
| 	private renderAttrInput( | ||||
|         id: ObjectID, key: AllI18nKeys, val: string | number | undefined, | ||||
|         change: (val: string, status: Status) => any, | ||||
|         step?: number, max?: number, min?: number | ||||
|     ) { | ||||
|         const handelFunc = (e: string) => { | ||||
|             if (this.props.status) { | ||||
|                 change(e, this.props.status); | ||||
|             } | ||||
|         } | ||||
|         if (step) { | ||||
|             return <AttrInput | ||||
|                 id={id} isNumber={true} step={step} keyI18n={key} | ||||
|                 value={val} max={max} min={min} | ||||
|                 valueChange={handelFunc} | ||||
|             /> | ||||
|         } else { | ||||
|             return <AttrInput | ||||
|                 id={id} keyI18n={key} value={val} | ||||
|                 valueChange={handelFunc} | ||||
|             /> | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 	private renderFrom(group: Group) { | ||||
| 		return <> | ||||
| 
 | ||||
| 			<Message i18nKey="Common.Attr.Title.Basic" isTitle first/> | ||||
| 
 | ||||
| 			{this.renderAttrInput( | ||||
|                 group.id, "Common.Attr.Key.Display.Name", group.displayName, | ||||
|                 (val, status) => { | ||||
|                     status.changeGroupAttrib(group.id, "displayName", val); | ||||
|                 } | ||||
|             )} | ||||
| 
 | ||||
|             <ColorInput | ||||
|                 keyI18n="Common.Attr.Key.Color" | ||||
|                 value={group.color} normal | ||||
|                 valueChange={(color) => { | ||||
|                     if (this.props.status) { | ||||
|                         this.props.status.changeGroupAttrib(group.id, "color", color); | ||||
|                     } | ||||
|                 }} | ||||
|             /> | ||||
| 
 | ||||
|             <LabelPicker | ||||
|                 keyI18n="Common.Attr.Key.Label" | ||||
|                 labels={group.allLabels()} | ||||
|                 labelAdd={(label) => { | ||||
|                     if (this.props.status) { | ||||
|                         this.props.status.addGroupLabel(group.id, label); | ||||
|                     } | ||||
|                 }} | ||||
|                 labelDelete={(label) => { | ||||
|                     if (this.props.status) { | ||||
|                         this.props.status.deleteGroupLabel(group.id, label); | ||||
|                     } | ||||
|                 }} | ||||
|             /> | ||||
|              | ||||
|             <TogglesInput | ||||
|                 keyI18n="Common.Attr.Key.Display" | ||||
|                 value={group.display} valueChange={(val) => { | ||||
|                     if (this.props.status) { | ||||
|                         this.props.status.changeGroupAttrib(group.id, "display", val); | ||||
|                     } | ||||
|                 }} | ||||
|             /> | ||||
| 
 | ||||
|             <TogglesInput | ||||
|                 keyI18n="Common.Attr.Key.Update" | ||||
|                 value={group.update} valueChange={(val) => { | ||||
|                     if (this.props.status) { | ||||
|                         this.props.status.changeGroupAttrib(group.id, "update", val); | ||||
|                     } | ||||
|                 }} | ||||
|             /> | ||||
| 
 | ||||
| 			<TogglesInput | ||||
| 				keyI18n="Common.Attr.Key.Delete" | ||||
| 				onIconName="delete" offIconName="delete" | ||||
| 				valueChange={() => { | ||||
| 					if (this.props.status) { | ||||
| 						this.props.status.model.deleteObject([group]); | ||||
| 						this.props.status.setFocusObject(new Set()); | ||||
| 					} | ||||
| 				}} | ||||
| 			/> | ||||
| 		</> | ||||
| 	} | ||||
| 
 | ||||
| 	public render(): ReactNode { | ||||
| 		if (this.props.status) { | ||||
|             if (this.props.status.focusObject.size <= 0) { | ||||
|                 return <Message i18nKey="Panel.Info.Group.Details.Attr.Error.Unspecified"/>; | ||||
|             } | ||||
|             if (this.props.status.focusObject.size > 1) { | ||||
|                 return <Message i18nKey="Common.Attr.Key.Error.Multiple"/>; | ||||
|             } | ||||
|             let id: ObjectID = ""; | ||||
|             this.props.status.focusObject.forEach((cid => id = cid)); | ||||
|              | ||||
|             let group = this.props.status!.model.getObjectById(id); | ||||
| 
 | ||||
|             if (group instanceof Group) { | ||||
|                 return this.renderFrom(group); | ||||
|             } else { | ||||
|                 return <Message i18nKey="Panel.Info.Group.Details.Attr.Error.Not.Group"/>; | ||||
|             } | ||||
|         } | ||||
| 		return <Message i18nKey="Panel.Info.Group.Details.Attr.Error.Unspecified"/>; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| export { GroupDetails } | ||||
| @ -1,8 +1,7 @@ | ||||
| import { Component, ReactNode } from "react"; | ||||
| import { AttrInput } from "@Component/AttrInput/AttrInput"; | ||||
| import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status"; | ||||
| import { AllI18nKeys } from "@Component/Localization/Localization"; | ||||
| import { ErrorMessage } from "@Component/ErrorMessage/ErrorMessage"; | ||||
| import { Message } from "@Component/Message/Message"; | ||||
| import { ColorInput } from "@Component/ColorInput/ColorInput"; | ||||
| import { Label } from "@Model/Label"; | ||||
| import { TogglesInput } from "@Component/TogglesInput/TogglesInput"; | ||||
| @ -14,6 +13,8 @@ class LabelDetails extends Component<IMixinStatusProps> { | ||||
|     private renderFrom(label: Label) { | ||||
|         return <> | ||||
| 
 | ||||
|             <Message i18nKey="Common.Attr.Title.Basic" isTitle first/> | ||||
|              | ||||
|             <AttrInput keyI18n="Common.Attr.Key.Display.Name" maxLength={15} value={label.name} valueChange={(value) => { | ||||
|                 if (this.props.status) { | ||||
|                     this.props.status.changeLabelAttrib(label, "name", value); | ||||
| @ -42,7 +43,7 @@ class LabelDetails extends Component<IMixinStatusProps> { | ||||
|                 return this.renderFrom(this.props.status.focusLabel); | ||||
|             } | ||||
|         } | ||||
| 		return <ErrorMessage i18nKey="Panel.Info.Label.Details.Error.Unspecified"/>; | ||||
| 		return <Message i18nKey="Panel.Info.Label.Details.Error.Unspecified"/>; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -6,7 +6,3 @@ div.label-list-panel-root { | ||||
|     padding: 10px; | ||||
|     box-sizing: border-box; | ||||
| } | ||||
| 
 | ||||
| div.label-list-pabel-err-msg { | ||||
|     padding-bottom: 5px; | ||||
| } | ||||
| @ -3,7 +3,7 @@ import { Component } from "react"; | ||||
| import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status"; | ||||
| import { useSetting, IMixinSettingProps } from "@Context/Setting"; | ||||
| import { Label } from "@Model/Label"; | ||||
| import { ErrorMessage } from "@Component/ErrorMessage/ErrorMessage"; | ||||
| import { Message } from "@Component/Message/Message"; | ||||
| import "./LabelList.scss"; | ||||
| 
 | ||||
| interface ILabelListProps { | ||||
| @ -31,10 +31,7 @@ class LabelList extends Component<ILabelListProps & IMixinStatusProps & IMixinSe | ||||
|             }} | ||||
|         > | ||||
|             {labels.length <=0 ?  | ||||
|                 <ErrorMessage | ||||
|                     className="label-list-pabel-err-msg" | ||||
|                     i18nKey="Panel.Info.Label.List.Error.Nodata" | ||||
|                 /> : null | ||||
|                 <Message i18nKey="Panel.Info.Label.List.Error.Nodata"/> : null | ||||
|             } | ||||
|             <LabelListComponent | ||||
|                 labels={labels} | ||||
|  | ||||
| @ -7,7 +7,7 @@ import { ObjectID } from "@Model/Renderer"; | ||||
| import "./ObjectList.scss"; | ||||
| 
 | ||||
| @useSetting | ||||
| @useStatusWithEvent("objectChange", "focusObjectChange", "rangeAttrChange") | ||||
| @useStatusWithEvent("objectChange", "focusObjectChange", "rangeAttrChange", "groupAttrChange") | ||||
| class ObjectList extends Component<IMixinStatusProps & IMixinSettingProps> { | ||||
| 
 | ||||
|     private renderList() { | ||||
| @ -43,6 +43,9 @@ class ObjectList extends Component<IMixinStatusProps & IMixinSettingProps> { | ||||
|                     if (item.key.slice(0, 1) === "R") { | ||||
|                         this.props.setting.layout.focus("RangeDetails"); | ||||
|                     } | ||||
|                     if (item.key.slice(0, 1) === "G") { | ||||
|                         this.props.setting.layout.focus("GroupDetails"); | ||||
|                     } | ||||
|                     this.props.setting.layout.focus("ObjectList"); | ||||
|                 } | ||||
|             }} | ||||
|  | ||||
| @ -1,12 +1,13 @@ | ||||
| import { ReactNode, Component, FunctionComponent } from "react"; | ||||
| import { Theme } from "@Component/Theme/Theme"; | ||||
| import { ErrorMessage } from "@Component/ErrorMessage/ErrorMessage"; | ||||
| import { Message } from "@Component/Message/Message"; | ||||
| import { RenderView } from "./RenderView/RenderView"; | ||||
| import { ObjectList } from "./ObjectList/ObjectList"; | ||||
| import { ObjectCommand } from "./ObjectList/ObjectCommand"; | ||||
| import { RangeDetails } from "./RangeDetails/RangeDetails"; | ||||
| import { LabelList } from "./LabelList/LabelList"; | ||||
| import { LabelDetails } from "./LabelDetails/LabelDetails"; | ||||
| import { GroupDetails } from "./GroupDetails/GroupDetails"; | ||||
| 
 | ||||
| interface IPanelInfo { | ||||
| 	nameKey: string; | ||||
| @ -25,6 +26,7 @@ type PanelId = "" | ||||
| | "RangeDetails" // 范围属性
 | ||||
| | "LabelList" // 标签列表
 | ||||
| | "LabelDetails" // 标签属性
 | ||||
| | "GroupDetails" // 群属性
 | ||||
| ; | ||||
| 
 | ||||
| const PanelInfoMap = new Map<PanelId, IPanelInfo>(); | ||||
| @ -35,19 +37,23 @@ PanelInfoMap.set("RenderView", { | ||||
| PanelInfoMap.set("ObjectList", { | ||||
|     nameKey: "Panel.Title.Object.List.View", introKay: "Panel.Info.Object.List.View", | ||||
|     class: ObjectList, header: ObjectCommand, hidePadding: true | ||||
| }) | ||||
| }); | ||||
| PanelInfoMap.set("RangeDetails", { | ||||
|     nameKey: "Panel.Title.Range.Details.View", introKay: "Panel.Info.Range.Details.View", | ||||
|     class: RangeDetails | ||||
| }) | ||||
| }); | ||||
| PanelInfoMap.set("LabelList", { | ||||
|     nameKey: "Panel.Title.Label.List.View", introKay: "Panel.Info.Label.List.View", | ||||
|     class: LabelList, hidePadding: true | ||||
| }) | ||||
| }); | ||||
| PanelInfoMap.set("LabelDetails", { | ||||
|     nameKey: "Panel.Title.Label.Details.View", introKay: "Panel.Info.Label.Details.View", | ||||
|     class: LabelDetails | ||||
| }) | ||||
| }); | ||||
| PanelInfoMap.set("GroupDetails", { | ||||
|     nameKey: "Panel.Title.Group.Details.View", introKay: "Panel.Info.Group.Details.View", | ||||
|     class: GroupDetails | ||||
| }); | ||||
| 
 | ||||
| function getPanelById(panelId: PanelId): ReactNode { | ||||
| 	switch (panelId) { | ||||
| @ -57,7 +63,7 @@ function getPanelById(panelId: PanelId): ReactNode { | ||||
| 				const C = info.class; | ||||
| 				return <C></C> | ||||
| 			} else return <Theme> | ||||
| 				<ErrorMessage i18nKey={"Panel.Info.Notfound"} options={{ id: panelId }}/> | ||||
| 				<Message i18nKey={"Panel.Info.Notfound"} options={{ id: panelId }}/> | ||||
| 			</Theme> | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -1,8 +1,8 @@ | ||||
| import { Component, ReactNode } from "react"; | ||||
| import { AttrInput } from "@Component/AttrInput/AttrInput"; | ||||
| import { useStatusWithEvent, IMixinStatusProps, Status } from "@Context/Status"; | ||||
| import { AllI18nKeys, Localization } from "@Component/Localization/Localization"; | ||||
| import { ErrorMessage } from "@Component/ErrorMessage/ErrorMessage"; | ||||
| import { AllI18nKeys } from "@Component/Localization/Localization"; | ||||
| import { Message } from "@Component/Message/Message"; | ||||
| import { Range } from "@Model/Range"; | ||||
| import { ObjectID } from "@Model/Renderer"; | ||||
| import { ColorInput } from "@Component/ColorInput/ColorInput"; | ||||
| @ -13,26 +13,11 @@ import "./RangeDetails.scss"; | ||||
| @useStatusWithEvent("rangeAttrChange", "focusObjectChange", "rangeLabelChange") | ||||
| class RangeDetails extends Component<IMixinStatusProps> { | ||||
| 
 | ||||
|     public readonly AttrI18nKey: AllI18nKeys[] = [ | ||||
|         "Common.Attr.Key.Display.Name", | ||||
|         "Common.Attr.Key.Label", | ||||
|         "Common.Attr.Key.Display", | ||||
|         "Common.Attr.Key.Update", | ||||
|         "Common.Attr.Key.Color", | ||||
|         "Common.Attr.Key.Position.X", | ||||
|         "Common.Attr.Key.Position.Y", | ||||
|         "Common.Attr.Key.Position.Z", | ||||
|         "Common.Attr.Key.Radius.X", | ||||
|         "Common.Attr.Key.Radius.Y", | ||||
|         "Common.Attr.Key.Radius.Z" | ||||
|     ] | ||||
| 
 | ||||
|     private renderAttrInput( | ||||
|         id: ObjectID, key: number, val: string | number | undefined, | ||||
|         id: ObjectID, key: AllI18nKeys, val: string | number | undefined, | ||||
|         change: (val: string, status: Status) => any, | ||||
|         step?: number, max?: number, min?: number | ||||
|     ) { | ||||
|         // console.log(id, key, val, step, max, min)
 | ||||
|         const handelFunc = (e: string) => { | ||||
|             if (this.props.status) { | ||||
|                 change(e, this.props.status); | ||||
| @ -40,13 +25,13 @@ class RangeDetails extends Component<IMixinStatusProps> { | ||||
|         } | ||||
|         if (step) { | ||||
|             return <AttrInput | ||||
|                 id={id} isNumber={true} step={step} keyI18n={this.AttrI18nKey[key]} | ||||
|                 id={id} isNumber={true} step={step} keyI18n={key} | ||||
|                 value={val} max={max} min={min} | ||||
|                 valueChange={handelFunc} | ||||
|             /> | ||||
|         } else { | ||||
|             return <AttrInput | ||||
|                 id={id} keyI18n={this.AttrI18nKey[key]} value={val} | ||||
|                 id={id} keyI18n={key} value={val} | ||||
|                 valueChange={handelFunc} | ||||
|             /> | ||||
|         } | ||||
| @ -54,14 +39,29 @@ class RangeDetails extends Component<IMixinStatusProps> { | ||||
| 
 | ||||
|     private renderFrom(range: Range) { | ||||
| 
 | ||||
|         let keyIndex = 0; | ||||
| 
 | ||||
|         return <> | ||||
|             {this.renderAttrInput(range.id, keyIndex ++, range.displayName, (val, status) => { | ||||
|                 status.changeRangeAttrib(range.id, "displayName", val); | ||||
|             })} | ||||
| 
 | ||||
|             <LabelPicker keyI18n={this.AttrI18nKey[keyIndex ++]} | ||||
|             <Message i18nKey="Common.Attr.Title.Basic" isTitle first/> | ||||
| 
 | ||||
|             {this.renderAttrInput( | ||||
|                 range.id, "Common.Attr.Key.Display.Name", range.displayName, | ||||
|                 (val, status) => { | ||||
|                     status.changeRangeAttrib(range.id, "displayName", val); | ||||
|                 } | ||||
|             )} | ||||
| 
 | ||||
|             <ColorInput | ||||
|                 keyI18n="Common.Attr.Key.Color" | ||||
|                 value={range.color} normal | ||||
|                 valueChange={(color) => { | ||||
|                     if (this.props.status) { | ||||
|                         this.props.status.changeRangeAttrib(range.id, "color", color); | ||||
|                     } | ||||
|                 }} | ||||
|             /> | ||||
| 
 | ||||
|             <LabelPicker | ||||
|                 keyI18n="Common.Attr.Key.Label" | ||||
|                 labels={range.allLabels()} | ||||
|                 labelAdd={(label) => { | ||||
|                     if (this.props.status) { | ||||
| @ -75,59 +75,94 @@ class RangeDetails extends Component<IMixinStatusProps> { | ||||
|                 }} | ||||
|             /> | ||||
|              | ||||
|             <TogglesInput keyI18n={this.AttrI18nKey[keyIndex ++]} value={range.display} valueChange={(val) => { | ||||
|                 if (this.props.status) { | ||||
|                     this.props.status.changeRangeAttrib(range.id, "display", val); | ||||
|                 } | ||||
|             }}/> | ||||
|             <TogglesInput | ||||
|                 keyI18n="Common.Attr.Key.Display" | ||||
|                 value={range.display} valueChange={(val) => { | ||||
|                     if (this.props.status) { | ||||
|                         this.props.status.changeRangeAttrib(range.id, "display", val); | ||||
|                     } | ||||
|                 }} | ||||
|             /> | ||||
| 
 | ||||
|             <TogglesInput keyI18n={this.AttrI18nKey[keyIndex ++]} value={range.update} valueChange={(val) => { | ||||
|                 if (this.props.status) { | ||||
|                     this.props.status.changeRangeAttrib(range.id, "update", val); | ||||
|                 } | ||||
|             }}/> | ||||
|             <TogglesInput | ||||
|                 keyI18n="Common.Attr.Key.Update" | ||||
|                 value={range.update} valueChange={(val) => { | ||||
|                     if (this.props.status) { | ||||
|                         this.props.status.changeRangeAttrib(range.id, "update", val); | ||||
|                     } | ||||
|                 }} | ||||
|             /> | ||||
| 
 | ||||
|             <ColorInput keyI18n={this.AttrI18nKey[keyIndex ++]} value={range.color} normal valueChange={(color) => { | ||||
|                 if (this.props.status) { | ||||
|                     this.props.status.changeRangeAttrib(range.id, "color", color); | ||||
|                 } | ||||
|             }}/> | ||||
|             <TogglesInput | ||||
| 				keyI18n="Common.Attr.Key.Delete" | ||||
| 				onIconName="delete" offIconName="delete" | ||||
| 				valueChange={() => { | ||||
| 					if (this.props.status) { | ||||
| 						this.props.status.model.deleteObject([range]); | ||||
| 						this.props.status.setFocusObject(new Set()); | ||||
| 					} | ||||
| 				}} | ||||
| 			/> | ||||
| 
 | ||||
|             {this.renderAttrInput(range.id, keyIndex ++, range.position[0], (val, status) => { | ||||
|                 range.position[0] = (val as any) / 1; | ||||
|                 status.changeRangeAttrib(range.id, "position", range.position); | ||||
|             }, .1)} | ||||
|             {this.renderAttrInput(range.id, keyIndex ++, range.position[1], (val, status) => { | ||||
|                 range.position[1] = (val as any) / 1; | ||||
|                 status.changeRangeAttrib(range.id, "position", range.position); | ||||
|             }, .1)} | ||||
|             {this.renderAttrInput(range.id, keyIndex ++, range.position[2], (val, status) => { | ||||
|                 range.position[2] = (val as any) / 1; | ||||
|                 status.changeRangeAttrib(range.id, "position", range.position); | ||||
|             }, .1)} | ||||
|             <Message i18nKey="Common.Attr.Title.Spatial" isTitle/> | ||||
| 
 | ||||
|             {this.renderAttrInput(range.id, keyIndex ++, range.radius[0], (val, status) => { | ||||
|                 range.radius[0] = (val as any) / 1; | ||||
|                 status.changeRangeAttrib(range.id, "radius", range.radius); | ||||
|             }, .1, undefined, 0)} | ||||
|             {this.renderAttrInput(range.id, keyIndex ++, range.radius[1], (val, status) => { | ||||
|                 range.radius[1] = (val as any) / 1; | ||||
|                 status.changeRangeAttrib(range.id, "radius", range.radius); | ||||
|             }, .1, undefined, 0)} | ||||
|             {this.renderAttrInput(range.id, keyIndex ++, range.radius[2], (val, status) => { | ||||
|                 range.radius[2] = (val as any) / 1; | ||||
|                 status.changeRangeAttrib(range.id, "radius", range.radius); | ||||
|             }, .1, undefined, 0)} | ||||
|             {this.renderAttrInput( | ||||
|                 range.id, "Common.Attr.Key.Position.X",  | ||||
|                 range.position[0], (val, status) => { | ||||
|                     range.position[0] = (val as any) / 1; | ||||
|                     status.changeRangeAttrib(range.id, "position", range.position); | ||||
|                 }, .1 | ||||
|             )} | ||||
| 
 | ||||
|             {this.renderAttrInput( | ||||
|                 range.id, "Common.Attr.Key.Position.Y", | ||||
|                 range.position[1],(val, status) => { | ||||
|                     range.position[1] = (val as any) / 1; | ||||
|                     status.changeRangeAttrib(range.id, "position", range.position); | ||||
|                 }, .1 | ||||
|             )} | ||||
| 
 | ||||
|             {this.renderAttrInput( | ||||
|                 range.id, "Common.Attr.Key.Position.Z", | ||||
|                 range.position[2], (val, status) => { | ||||
|                     range.position[2] = (val as any) / 1; | ||||
|                     status.changeRangeAttrib(range.id, "position", range.position); | ||||
|                 }, .1 | ||||
|             )} | ||||
| 			 | ||||
|             {this.renderAttrInput( | ||||
|                 range.id, "Common.Attr.Key.Radius.X", | ||||
|                 range.radius[0], (val, status) => { | ||||
|                     range.radius[0] = (val as any) / 1; | ||||
|                     status.changeRangeAttrib(range.id, "radius", range.radius); | ||||
|                 }, .1, undefined, 0 | ||||
|             )} | ||||
| 
 | ||||
|             {this.renderAttrInput( | ||||
|                 range.id, "Common.Attr.Key.Radius.Y", | ||||
|                 range.radius[1], (val, status) => { | ||||
|                     range.radius[1] = (val as any) / 1; | ||||
|                     status.changeRangeAttrib(range.id, "radius", range.radius); | ||||
|                 }, .1, undefined, 0 | ||||
|             )} | ||||
| 
 | ||||
|             {this.renderAttrInput( | ||||
|                 range.id, "Common.Attr.Key.Radius.Z", | ||||
|                 range.radius[2], (val, status) => { | ||||
|                     range.radius[2] = (val as any) / 1; | ||||
|                     status.changeRangeAttrib(range.id, "radius", range.radius); | ||||
|                 }, .1, undefined, 0 | ||||
|             )} | ||||
| 		</> | ||||
|     } | ||||
| 
 | ||||
| 	public render(): ReactNode { | ||||
|         if (this.props.status) { | ||||
|             if (this.props.status.focusObject.size <= 0) { | ||||
|                 return <ErrorMessage i18nKey="Panel.Info.Range.Details.Attr.Error.Unspecified"/>; | ||||
|                 return <Message i18nKey="Panel.Info.Range.Details.Attr.Error.Unspecified"/>; | ||||
|             } | ||||
|             if (this.props.status.focusObject.size > 1) { | ||||
|                 return <ErrorMessage i18nKey="Common.Attr.Key.Error.Multiple"/>; | ||||
|                 return <Message i18nKey="Common.Attr.Key.Error.Multiple"/>; | ||||
|             } | ||||
|             let id: ObjectID = ""; | ||||
|             this.props.status.focusObject.forEach((cid => id = cid)); | ||||
| @ -137,10 +172,10 @@ class RangeDetails extends Component<IMixinStatusProps> { | ||||
|             if (range instanceof Range) { | ||||
|                 return this.renderFrom(range); | ||||
|             } else { | ||||
|                 return <ErrorMessage i18nKey="Panel.Info.Range.Details.Attr.Error.Not.Range"/>; | ||||
|                 return <Message i18nKey="Panel.Info.Range.Details.Attr.Error.Not.Range"/>; | ||||
|             } | ||||
|         } | ||||
| 		return <ErrorMessage i18nKey="Panel.Info.Range.Details.Attr.Error.Unspecified"/>; | ||||
| 		return <Message i18nKey="Panel.Info.Range.Details.Attr.Error.Unspecified"/>; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user