Compare commits
	
		
			No commits in common. "41b29f61bc3eeca3921ec2d3bd8119279789e9d8" and "99fa5c698aecece761773a5f76ad24207944c2e5" have entirely different histories.
		
	
	
		
			41b29f61bc
			...
			99fa5c698a
		
	
		
| @ -1,103 +0,0 @@ | |||||||
| @import "../Theme/Theme.scss"; |  | ||||||
| 
 |  | ||||||
| $line-min-height: 24px; |  | ||||||
| $root-min-height: 26px; |  | ||||||
| 
 |  | ||||||
| div.attr-input { |  | ||||||
| 	width: 100%; |  | ||||||
| 	display: flex; |  | ||||||
| 	min-height: $line-min-height; |  | ||||||
| 	padding: 5px 0; |  | ||||||
| 
 |  | ||||||
| 	div.input-intro { |  | ||||||
| 		width: 50%; |  | ||||||
| 		height: 100%; |  | ||||||
| 		max-width: 220px; |  | ||||||
| 		display: flex; |  | ||||||
| 		align-items: center; |  | ||||||
|         padding-right: 5px; |  | ||||||
|         box-sizing: border-box; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
|     div.root-content { |  | ||||||
|         width: 50%; |  | ||||||
|         height: 100%; |  | ||||||
|         max-width: 180px; |  | ||||||
|         min-height: $root-min-height; |  | ||||||
| 
 |  | ||||||
|         div.input-content { |  | ||||||
|             box-sizing: border-box; |  | ||||||
|             border: 1px solid transparent; |  | ||||||
|             border-radius: 3px; |  | ||||||
|             overflow: hidden; |  | ||||||
|             display: flex; |  | ||||||
|             justify-content: space-between; |  | ||||||
|             align-items: center; |  | ||||||
|             min-height: $root-min-height; |  | ||||||
|      |  | ||||||
|             input { |  | ||||||
|                 width: 100%; |  | ||||||
|                 height: 100%; |  | ||||||
|                 border: none; |  | ||||||
|                 outline:none; |  | ||||||
|                 min-height: $line-min-height; |  | ||||||
|             }; |  | ||||||
|      |  | ||||||
|             input:focus { |  | ||||||
|                 border: none; |  | ||||||
|             } |  | ||||||
|      |  | ||||||
|             div.button-left, div.button-right { |  | ||||||
|                 min-height: $line-min-height; |  | ||||||
|                 height: 100%; |  | ||||||
|                 display: flex; |  | ||||||
|                 justify-content: center; |  | ||||||
|                 align-items: center; |  | ||||||
|                 vertical-align: middle; |  | ||||||
|                 cursor: pointer; |  | ||||||
|                 user-select: none; |  | ||||||
|                 padding: 0 3px; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|      |  | ||||||
|         div.input-content.error { |  | ||||||
|             border: 1px solid $lt-red; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         div.input-content.focus { |  | ||||||
|             border: 1px solid $lt-blue; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         div.err-message { |  | ||||||
|             color: $lt-red; |  | ||||||
|             padding-top: 5px; |  | ||||||
|             min-height: $line-min-height; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| div.dark.attr-input { |  | ||||||
| 
 |  | ||||||
| 	div.input-content, |  | ||||||
| 	div.input-content input { |  | ||||||
| 		background-color: $lt-bg-color-lvl3-dark; |  | ||||||
| 		color: $lt-font-color-normal-dark; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	div.button-left:hover, div.button-right:hover { |  | ||||||
| 		background-color: $lt-bg-color-lvl2-dark; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| div.light.attr-input { |  | ||||||
| 
 |  | ||||||
| 	div.input-content, |  | ||||||
| 	div.input-content input { |  | ||||||
| 		background-color: $lt-bg-color-lvl3-light; |  | ||||||
| 		color: $lt-font-color-normal-light; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	div.button-left:hover, div.button-right:hover { |  | ||||||
| 		background-color: $lt-bg-color-lvl2-light; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @ -1,173 +0,0 @@ | |||||||
| import { Component, ReactNode } from "react"; |  | ||||||
| import { FontLevel, Theme } from "@Component/Theme/Theme"; |  | ||||||
| import "./AttrInput.scss"; |  | ||||||
| import { Icon } from "@fluentui/react"; |  | ||||||
| import { Localization, AllI18nKeys } from "@Component/Localization/Localization"; |  | ||||||
| import { ObjectID } from "@Model/Renderer"; |  | ||||||
| 
 |  | ||||||
| interface IAttrInputProps { |  | ||||||
|     id?: ObjectID; |  | ||||||
|     keyI18n: AllI18nKeys; |  | ||||||
|     infoI18n?: AllI18nKeys; |  | ||||||
|     value?: number | string; |  | ||||||
| 	isNumber?: boolean; |  | ||||||
|     maxLength?: number; |  | ||||||
|     max?: number; |  | ||||||
|     min?: number; |  | ||||||
|     step?: number; |  | ||||||
|     disable?: boolean; |  | ||||||
|     disableI18n?: AllI18nKeys; |  | ||||||
|     valueChange?: (value: this["isNumber"] extends true ? number : string) => any; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class AttrInput extends Component<IAttrInputProps> { |  | ||||||
| 
 |  | ||||||
|     private value: string = ""; |  | ||||||
|     private error: ReactNode; |  | ||||||
| 
 |  | ||||||
|     private check(value: string): ReactNode { |  | ||||||
| 
 |  | ||||||
|         // 长度校验
 |  | ||||||
|         const maxLength = this.props.maxLength ?? 32; |  | ||||||
|         if (value.length > maxLength) { |  | ||||||
|             return <Localization i18nKey="Input.Error.Length" options={{ num: maxLength.toString() }} /> |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if (this.props.isNumber) { |  | ||||||
|             const praseNumber = (value as any) / 1; |  | ||||||
| 
 |  | ||||||
|             // 数字校验
 |  | ||||||
|             if (isNaN(praseNumber) || /\.0*$/.test(value)) { |  | ||||||
|                 return <Localization i18nKey="Input.Error.Not.Number" /> |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             // 最大值校验
 |  | ||||||
|             if (this.props.max !== undefined && praseNumber > this.props.max) { |  | ||||||
|                 return <Localization i18nKey="Input.Error.Max" options={{ num: this.props.max.toString() }} /> |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             // 最小值校验
 |  | ||||||
|             if (this.props.min !== undefined && praseNumber < this.props.min) { |  | ||||||
|                 return <Localization i18nKey="Input.Error.Min" options={{ num: this.props.min.toString() }} /> |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|         } |  | ||||||
|         return undefined; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private handelValueChange = () => { |  | ||||||
|         if (!this.error && this.props.valueChange) { |  | ||||||
|             if (this.props.isNumber) { |  | ||||||
|                 let numberVal = (this.value as any) * 10000; |  | ||||||
|                 this.value = (Math.round(numberVal) / 10000).toString(); |  | ||||||
|             } |  | ||||||
|             this.props.valueChange(this.value); |  | ||||||
|         } |  | ||||||
|         this.forceUpdate(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private changeValue = (direction: number) => { |  | ||||||
|         if (this.error) { |  | ||||||
|             return; |  | ||||||
|         } else { |  | ||||||
|             let newVal = (this.value as any / 1) + (this.props.step ?? 1) * direction; |  | ||||||
| 
 |  | ||||||
|             // 最大值校验
 |  | ||||||
|             if (this.props.max !== undefined && newVal > this.props.max) { |  | ||||||
|                 newVal = this.props.max; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             // 最小值校验
 |  | ||||||
|             if (this.props.min !== undefined && newVal < this.props.min) { |  | ||||||
|                 newVal = this.props.min; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             this.value = newVal.toString(); |  | ||||||
|             this.handelValueChange() |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private renderInput() { |  | ||||||
|         return <> |  | ||||||
|             <div className={"input-content" + (this.error ? ` error` : "")}> |  | ||||||
|                 { |  | ||||||
|                     this.props.isNumber ? <div |  | ||||||
|                         className="button-left" |  | ||||||
|                         onClick={() => this.changeValue(-1)} |  | ||||||
|                     > |  | ||||||
|                         <Icon iconName="ChevronLeft"></Icon> |  | ||||||
|                     </div> : null |  | ||||||
|                 } |  | ||||||
|                 <input |  | ||||||
|                     className="input" |  | ||||||
|                     value={this.value} |  | ||||||
|                     style={{ |  | ||||||
|                         padding: this.props.isNumber ? "0 3px" : "0 8px" |  | ||||||
|                     }} |  | ||||||
|                     onChange={(e) => { |  | ||||||
|                         this.value = e.target.value; |  | ||||||
|                         this.error = this.check(e.target.value); |  | ||||||
|                         this.handelValueChange(); |  | ||||||
|                     }} |  | ||||||
|                 ></input> |  | ||||||
|                 { |  | ||||||
|                     this.props.isNumber ? <div |  | ||||||
|                         className="button-right" |  | ||||||
|                         onClick={() => this.changeValue(1)} |  | ||||||
|                     > |  | ||||||
|                         <Icon iconName="ChevronRight"></Icon> |  | ||||||
|                     </div> : null |  | ||||||
|                 } |  | ||||||
|             </div> |  | ||||||
|             {  |  | ||||||
|                 this.error ?  |  | ||||||
|                     <div className="err-message"> |  | ||||||
|                         {this.error} |  | ||||||
|                     </div> : null |  | ||||||
|             } |  | ||||||
|         </> |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public shouldComponentUpdate(nextProps: IAttrInputProps) { |  | ||||||
| 
 |  | ||||||
|         // ID 都为空时更新
 |  | ||||||
|         if (!nextProps.id && !this.props.id) { |  | ||||||
|             this.updateValueFromProps(nextProps.value); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // ID 变换时更新 State 到最新的 Props
 |  | ||||||
|         if (nextProps.id !== this.props.id) { |  | ||||||
|             this.updateValueFromProps(nextProps.value); |  | ||||||
|         } |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private updateValueFromProps(val: IAttrInputProps["value"]) { |  | ||||||
|         const value = val ?? (this.props.isNumber ? "0" : ""); |  | ||||||
|         this.value = value.toString(); |  | ||||||
|         this.error = this.check(value.toString()); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| 	public render(): ReactNode { |  | ||||||
| 
 |  | ||||||
| 		return <Theme |  | ||||||
|             className="attr-input" |  | ||||||
|             fontLevel={FontLevel.normal} |  | ||||||
|         > |  | ||||||
|             <div className="input-intro"> |  | ||||||
|                 <Localization i18nKey={this.props.keyI18n}/> |  | ||||||
|             </div> |  | ||||||
|             <div className="root-content"> |  | ||||||
|                 { |  | ||||||
|                     this.props.disable ?  |  | ||||||
|                         this.props.disableI18n ?  |  | ||||||
|                             <Localization i18nKey={this.props.disableI18n}/> : |  | ||||||
|                             <div>{this.props.value}</div> : |  | ||||||
|                         this.renderInput() |  | ||||||
|                 } |  | ||||||
|             </div> |  | ||||||
|         </Theme> |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export { AttrInput }; |  | ||||||
| @ -2,7 +2,7 @@ import { BackgroundLevel, Theme } from "@Component/Theme/Theme"; | |||||||
| import { DirectionalHint, IconButton } from "@fluentui/react"; | import { DirectionalHint, IconButton } from "@fluentui/react"; | ||||||
| import { LocalizationTooltipHost } from "../Localization/LocalizationTooltipHost"; | import { LocalizationTooltipHost } from "../Localization/LocalizationTooltipHost"; | ||||||
| import { useSetting, IMixinSettingProps } from "@Context/Setting"; | import { useSetting, IMixinSettingProps } from "@Context/Setting"; | ||||||
| import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status"; | import { useStatus, IMixinStatusProps } from "@Context/Status"; | ||||||
| import { AllI18nKeys } from "../Localization/Localization"; | import { AllI18nKeys } from "../Localization/Localization"; | ||||||
| import { Component, ReactNode } from "react"; | import { Component, ReactNode } from "react"; | ||||||
| import { MouseMod } from "@GLRender/ClassicRenderer"; | import { MouseMod } from "@GLRender/ClassicRenderer"; | ||||||
| @ -12,10 +12,26 @@ interface ICommandBarProps { | |||||||
|     width: number; |     width: number; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @useStatus | ||||||
| @useSetting | @useSetting | ||||||
| @useStatusWithEvent("mouseModChange") |  | ||||||
| class CommandBar extends Component<ICommandBarProps & IMixinSettingProps & IMixinStatusProps> { | class CommandBar extends Component<ICommandBarProps & IMixinSettingProps & IMixinStatusProps> { | ||||||
| 
 | 
 | ||||||
|  |     private handelChange = () => { | ||||||
|  |         this.forceUpdate(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     componentDidMount() { | ||||||
|  |         if (this.props.status) { | ||||||
|  |             this.props.status.on("mouseModChange", this.handelChange) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     componentWillUnmount() { | ||||||
|  |         if (this.props.status) { | ||||||
|  |             this.props.status.off("mouseModChange", this.handelChange) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     render(): ReactNode { |     render(): ReactNode { | ||||||
| 
 | 
 | ||||||
|         const mouseMod = this.props.status?.mouseMod ?? MouseMod.Drag; |         const mouseMod = this.props.status?.mouseMod ?? MouseMod.Drag; | ||||||
| @ -46,16 +62,12 @@ class CommandBar extends Component<ICommandBarProps & IMixinSettingProps & IMixi | |||||||
|                 {this.getRenderButton({ |                 {this.getRenderButton({ | ||||||
|                     iconName: "WebAppBuilderFragmentCreate", |                     iconName: "WebAppBuilderFragmentCreate", | ||||||
|                     i18NKey: "Command.Bar.Add.Group.Info", |                     i18NKey: "Command.Bar.Add.Group.Info", | ||||||
|                     click: () => { |                     click: () => this.props.status ? this.props.status.newGroup() : undefined | ||||||
|                         this.props.status ? this.props.status.newGroup() : undefined; |  | ||||||
|                     } |  | ||||||
|                 })} |                 })} | ||||||
|                 {this.getRenderButton({ |                 {this.getRenderButton({ | ||||||
|                     iconName: "CubeShape", |                     iconName: "CubeShape", | ||||||
|                     i18NKey: "Command.Bar.Add.Range.Info", |                     i18NKey: "Command.Bar.Add.Range.Info", | ||||||
|                     click: () => { |                     click: () => this.props.status ? this.props.status.newRange() : undefined | ||||||
|                         this.props.status ? this.props.status.newRange() : undefined; |  | ||||||
|                     } |  | ||||||
|                 })} |                 })} | ||||||
|                 {this.getRenderButton({ iconName: "StepSharedAdd", i18NKey: "Command.Bar.Add.Behavior.Info" })} |                 {this.getRenderButton({ iconName: "StepSharedAdd", i18NKey: "Command.Bar.Add.Behavior.Info" })} | ||||||
|                 {this.getRenderButton({ iconName: "Tag", i18NKey: "Command.Bar.Add.Tag.Info" })} |                 {this.getRenderButton({ iconName: "Tag", i18NKey: "Command.Bar.Add.Tag.Info" })} | ||||||
|  | |||||||
| @ -27,7 +27,7 @@ div.app-container { | |||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		div:hover { | 		div:hover { | ||||||
| 			background-color: $lt-blue; | 			background-color: blue; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -83,7 +83,7 @@ div.app-container { | |||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		div.app-tab-header-item.active { | 		div.app-tab-header-item.active { | ||||||
| 			border: .8px solid $lt-blue; | 			border: .8px solid blue; | ||||||
| 			transition: none; | 			transition: none; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| @ -141,7 +141,7 @@ div.app-container { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	div.app-panel-root.active { | 	div.app-panel-root.active { | ||||||
| 		border: .8px solid $lt-blue !important; | 		border: .8px solid blue !important; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -11,7 +11,7 @@ div.details-list { | |||||||
|         min-height: 30px; |         min-height: 30px; | ||||||
| 
 | 
 | ||||||
|         div.details-list-value { |         div.details-list-value { | ||||||
|             padding: 5px 5px; |             padding: 5px 10px; | ||||||
|             display: flex; |             display: flex; | ||||||
|             justify-content: center; |             justify-content: center; | ||||||
|             align-items: center; |             align-items: center; | ||||||
| @ -19,7 +19,6 @@ div.details-list { | |||||||
| 
 | 
 | ||||||
|         div.details-list-checkbox { |         div.details-list-checkbox { | ||||||
|             display: flex; |             display: flex; | ||||||
|             flex-shrink: 0; |  | ||||||
|             width: 30px; |             width: 30px; | ||||||
|             align-items: center; |             align-items: center; | ||||||
|             justify-content: center; |             justify-content: center; | ||||||
|  | |||||||
| @ -62,8 +62,8 @@ class HeaderBar extends Component< | |||||||
|         } |         } | ||||||
|         if (status) { |         if (status) { | ||||||
|             status.archive.on("save", this.changeListener); |             status.archive.on("save", this.changeListener); | ||||||
|             status.on("physicsLoop", this.physicsFpsCalc); |             status.model.on("loop", this.physicsFpsCalc); | ||||||
|             status.on("renderLoop", this.renderFpsCalc); |             status.renderer.on("loop", this.renderFpsCalc); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -74,8 +74,8 @@ class HeaderBar extends Component< | |||||||
|         } |         } | ||||||
|         if (status) { |         if (status) { | ||||||
|             status.archive.off("save", this.changeListener); |             status.archive.off("save", this.changeListener); | ||||||
|             status.off("physicsLoop", this.physicsFpsCalc); |             status.model.off("loop", this.physicsFpsCalc); | ||||||
|             status.off("renderLoop", this.renderFpsCalc); |             status.renderer.off("loop", this.renderFpsCalc); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,8 +1,5 @@ | |||||||
| @import "@fluentui/react/dist/sass/References"; | @import "@fluentui/react/dist/sass/References"; | ||||||
| 
 | 
 | ||||||
| $lt-blue: rgb(81, 79, 235); |  | ||||||
| $lt-red: rgb(240, 94, 94); |  | ||||||
| 
 |  | ||||||
| $lt-font-size-normal: 13px; | $lt-font-size-normal: 13px; | ||||||
| $lt-font-size-lvl3: $ms-font-size-16; | $lt-font-size-lvl3: $ms-font-size-16; | ||||||
| $lt-font-size-lvl2: $ms-font-size-18; | $lt-font-size-lvl2: $ms-font-size-18; | ||||||
|  | |||||||
| @ -1,8 +1,8 @@ | |||||||
| import { createContext, Component, FunctionComponent, useState, useEffect, ReactNode } from "react"; | import { createContext, Component, FunctionComponent } from "react"; | ||||||
| import { Emitter } from "@Model/Emitter"; | import { Emitter } from "@Model/Emitter"; | ||||||
| import { Model, ObjectID } from "@Model/Model"; | import { Model, ObjectID } from "@Model/Model"; | ||||||
| import { Range } from "@Model/Range"; |  | ||||||
| import { Archive } from "@Model/Archive"; | import { Archive } from "@Model/Archive"; | ||||||
|  | import { CtrlObject } from "@Model/CtrlObject"; | ||||||
| import { AbstractRenderer } from "@Model/Renderer"; | import { AbstractRenderer } from "@Model/Renderer"; | ||||||
| import { ClassicRenderer, MouseMod } from "@GLRender/ClassicRenderer"; | import { ClassicRenderer, MouseMod } from "@GLRender/ClassicRenderer"; | ||||||
| import { Setting } from "./Setting"; | import { Setting } from "./Setting"; | ||||||
| @ -16,17 +16,10 @@ function randomColor() { | |||||||
|     ] |     ] | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| interface IStatusEvent { | class Status extends Emitter<{ | ||||||
|     renderLoop: number; |     mouseModChange: MouseMod, | ||||||
|     physicsLoop: number; |     focusObjectChange: Set<ObjectID> | ||||||
|     mouseModChange: void; | }> { | ||||||
|     focusObjectChange: void; |  | ||||||
|     objectChange: void; |  | ||||||
|     labelChange: void; |  | ||||||
|     rangeAttrChange: void; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class Status extends Emitter<IStatusEvent> { |  | ||||||
| 
 | 
 | ||||||
|     public setting: Setting = undefined as any; |     public setting: Setting = undefined as any; | ||||||
| 
 | 
 | ||||||
| @ -55,47 +48,12 @@ class Status extends Emitter<IStatusEvent> { | |||||||
|      */ |      */ | ||||||
|     public focusObject: Set<ObjectID> = new Set(); |     public focusObject: Set<ObjectID> = new Set(); | ||||||
| 
 | 
 | ||||||
|     public constructor() { |  | ||||||
|         super(); |  | ||||||
| 
 |  | ||||||
|         // 循环事件
 |  | ||||||
|         this.model.on("loop", (t) => { this.emit("physicsLoop", t) }); |  | ||||||
| 
 |  | ||||||
|         // 对象变化事件
 |  | ||||||
|         this.model.on("objectChange", () => this.emit("objectChange")); |  | ||||||
|         this.model.on("labelChange", () => this.emit("labelChange")); |  | ||||||
| 
 |  | ||||||
|         // 对象变换时执行渲染,更新渲染器数据
 |  | ||||||
|         this.on("objectChange", () => { |  | ||||||
|             this.model.draw(); |  | ||||||
|         }) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public bindRenderer(renderer: AbstractRenderer) { |  | ||||||
|         this.renderer = renderer; |  | ||||||
|         this.renderer.on("loop", (t) => { this.emit("renderLoop", t) }); |  | ||||||
|         this.model.bindRenderer(this.renderer); |  | ||||||
|     }  |  | ||||||
| 
 |  | ||||||
|     /** |     /** | ||||||
|      * 更新焦点对象 |      * 更新焦点对象 | ||||||
|      */ |      */ | ||||||
|     public setFocusObject(focusObject: Set<ObjectID>) { |     public setFocusObject(focusObject: Set<ObjectID>) { | ||||||
|         this.focusObject = focusObject; |         this.focusObject = focusObject; | ||||||
|         this.emit("focusObjectChange"); |         this.emit("focusObjectChange", this.focusObject); | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * 修改范围属性 |  | ||||||
|      */ |  | ||||||
|     public changeRangeAttrib<K extends keyof Range> |  | ||||||
|     (id: ObjectID, key: K, val: Range[K]) { |  | ||||||
|         const range = this.model.getObjectById(id); |  | ||||||
|         if (range && range instanceof Range) { |  | ||||||
|             range[key] = val; |  | ||||||
|             this.emit("rangeAttrChange"); |  | ||||||
|             this.model.draw(); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -129,7 +87,7 @@ class Status extends Emitter<IStatusEvent> { | |||||||
|             this.renderer.mouseMod = mod; |             this.renderer.mouseMod = mod; | ||||||
|             this.renderer.setMouseIcon(); |             this.renderer.setMouseIcon(); | ||||||
|         } |         } | ||||||
|         this.emit("mouseModChange"); |         this.emit("mouseModChange", mod); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| @ -158,55 +116,7 @@ function useStatus<R extends RenderComponent>(components: R): R { | |||||||
|     }) as any; |     }) as any; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function useStatusWithEvent(...events: Array<keyof IStatusEvent>) { |  | ||||||
|     return <R extends RenderComponent>(components: R): R => { |  | ||||||
|         const C = components as any; |  | ||||||
|         return class extends Component<R> { |  | ||||||
| 
 |  | ||||||
|             private status: Status | undefined; |  | ||||||
|             private isEventMount: boolean = false; |  | ||||||
| 
 |  | ||||||
|             private handelChange = () => { |  | ||||||
|                 this.forceUpdate(); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             private mountEvent() { |  | ||||||
|                 if (this.status && !this.isEventMount) { |  | ||||||
|                     this.isEventMount = true; |  | ||||||
|                     console.log("event mount"); |  | ||||||
|                     for (let i = 0; i < events.length; i++) { |  | ||||||
|                         this.status.on(events[i], this.handelChange); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             private unmountEvent() { |  | ||||||
|                 if (this.status) { |  | ||||||
|                     for (let i = 0; i < events.length; i++) { |  | ||||||
|                         this.status.off(events[i], this.handelChange); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             public render(): ReactNode { |  | ||||||
|                 return <StatusConsumer> |  | ||||||
|                     {(status: Status) => { |  | ||||||
|                         this.status = status; |  | ||||||
|                         this.mountEvent(); |  | ||||||
|                         return <C {...this.props} status={status}></C>; |  | ||||||
|                     }} |  | ||||||
|                 </StatusConsumer> |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             public componentWillUnmount() { |  | ||||||
|                 this.unmountEvent(); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|         } as any; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export { | export { | ||||||
|     Status, StatusContext, useStatus, useStatusWithEvent, |     Status, StatusContext, useStatus, | ||||||
|     IMixinStatusProps, StatusProvider, StatusConsumer |     IMixinStatusProps, StatusProvider, StatusConsumer | ||||||
| }; | }; | ||||||
| @ -19,10 +19,6 @@ const EN_US = { | |||||||
|     "Command.Bar.Add.Tag.Info": "Add label object", |     "Command.Bar.Add.Tag.Info": "Add label object", | ||||||
|     "Command.Bar.Camera.Info": "Renderer settings", |     "Command.Bar.Camera.Info": "Renderer settings", | ||||||
|     "Command.Bar.Setting.Info": "Global Settings", |     "Command.Bar.Setting.Info": "Global Settings", | ||||||
|     "Input.Error.Not.Number": "Please key in numbers", |  | ||||||
|     "Input.Error.Max": "Enter value must be less than {num}", |  | ||||||
|     "Input.Error.Min": "Enter value must be greater than {num}", |  | ||||||
|     "Input.Error.Length": "The length of the input content must be less than {num}", |  | ||||||
|     "Object.List.New.Group": "Group object {id}", |     "Object.List.New.Group": "Group object {id}", | ||||||
|     "Object.List.New.Range": "Range object {id}", |     "Object.List.New.Range": "Range object {id}", | ||||||
|     "Object.List.No.Data": "There are no objects in the model, click the button to create it", |     "Object.List.No.Data": "There are no objects in the model, click the button to create it", | ||||||
| @ -32,14 +28,6 @@ const EN_US = { | |||||||
|     "Panel.Info.Render.View": "Live simulation results preview", |     "Panel.Info.Render.View": "Live simulation results preview", | ||||||
|     "Panel.Title.Object.List.View": "Object list", |     "Panel.Title.Object.List.View": "Object list", | ||||||
|     "Panel.Info.Object.List.View": "Edit View All Object Properties", |     "Panel.Info.Object.List.View": "Edit View All Object Properties", | ||||||
|     "Panel.Title.Range.Details.View": "Range attributes", | 
 | ||||||
|     "Panel.Info.Range.Details.View": "Edit View Range attributes", |  | ||||||
|     "Common.Attr.Key.Display.Name": "Display name", |  | ||||||
|     "Common.Attr.Key.Position.X": "Position X", |  | ||||||
|     "Common.Attr.Key.Position.Y": "Position Y", |  | ||||||
|     "Common.Attr.Key.Position.Z": "Position Z", |  | ||||||
|     "Common.Attr.Key.Error.Multiple": "Cannot edit multiple values", |  | ||||||
|     "Panel.Info.Range.Details.Attr.Error.Not.Range": "The focus object is not a Range", |  | ||||||
|     "Panel.Info.Range.Details.Attr.Error.Unspecified": "Unspecified range object", |  | ||||||
| } | } | ||||||
| export default EN_US; | export default EN_US; | ||||||
| @ -19,10 +19,6 @@ const ZH_CN = { | |||||||
|     "Command.Bar.Add.Tag.Info": "添加标签对象", |     "Command.Bar.Add.Tag.Info": "添加标签对象", | ||||||
|     "Command.Bar.Camera.Info": "渲染器设置", |     "Command.Bar.Camera.Info": "渲染器设置", | ||||||
|     "Command.Bar.Setting.Info": "全局设置", |     "Command.Bar.Setting.Info": "全局设置", | ||||||
|     "Input.Error.Not.Number": "请输入数字", |  | ||||||
|     "Input.Error.Max": "输入数值须小于 {number}", |  | ||||||
|     "Input.Error.Min": "输入数值须大于 {number}", |  | ||||||
|     "Input.Error.Length": "输入内容长度须小于 {number}", |  | ||||||
|     "Object.List.New.Group": "组对象 {id}", |     "Object.List.New.Group": "组对象 {id}", | ||||||
|     "Object.List.New.Range": "范围对象 {id}", |     "Object.List.New.Range": "范围对象 {id}", | ||||||
|     "Object.List.No.Data": "模型中没有任何对象,点击按钮以创建", |     "Object.List.No.Data": "模型中没有任何对象,点击按钮以创建", | ||||||
| @ -32,14 +28,5 @@ const ZH_CN = { | |||||||
|     "Panel.Info.Render.View": "实时仿真结果预览", |     "Panel.Info.Render.View": "实时仿真结果预览", | ||||||
|     "Panel.Title.Object.List.View": "对象列表", |     "Panel.Title.Object.List.View": "对象列表", | ||||||
|     "Panel.Info.Object.List.View": "编辑查看全部对象属性", |     "Panel.Info.Object.List.View": "编辑查看全部对象属性", | ||||||
|     "Panel.Title.Range.Details.View": "范围属性", |  | ||||||
|     "Panel.Info.Range.Details.View": "编辑查看范围属性", |  | ||||||
|     "Common.Attr.Key.Display.Name": "显示名称", |  | ||||||
|     "Common.Attr.Key.Position.X": "X 坐标", |  | ||||||
|     "Common.Attr.Key.Position.Y": "Y 坐标", |  | ||||||
|     "Common.Attr.Key.Position.Z": "Z 坐标", |  | ||||||
|     "Common.Attr.Key.Error.Multiple": "无法编辑多重数值", |  | ||||||
|     "Panel.Info.Range.Details.Attr.Error.Not.Range": "焦点对象不是一个范围", |  | ||||||
|     "Panel.Info.Range.Details.Attr.Error.Unspecified": "未指定范围对象", |  | ||||||
| } | } | ||||||
| export default ZH_CN; | export default ZH_CN; | ||||||
| @ -74,7 +74,7 @@ class Layout extends Emitter<ILayoutEvent> { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	public focus = (panelId: string) => { | 	public focus = (panelId: string) => { | ||||||
| 		if (panelId === "" && this.focusId !== "") { | 		if (panelId === "") { | ||||||
| 			this.focusId = panelId; | 			this.focusId = panelId; | ||||||
| 			this.emit("switchTab", this); | 			this.emit("switchTab", this); | ||||||
| 		} | 		} | ||||||
| @ -89,16 +89,12 @@ class Layout extends Emitter<ILayoutEvent> { | |||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 				if (index >= 0) { | 				if (index >= 0) { | ||||||
| 					if (layout.focusPanel === panelId && this.focusId === panelId) { |  | ||||||
| 						return true; |  | ||||||
| 					} else { |  | ||||||
| 					layout.focusPanel = panelId; | 					layout.focusPanel = panelId; | ||||||
| 					this.focusId = panelId; | 					this.focusId = panelId; | ||||||
| 					this.emit("switchTab", this); | 					this.emit("switchTab", this); | ||||||
| 					return true; | 					return true; | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			} |  | ||||||
| 		}) | 		}) | ||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -39,7 +39,7 @@ class Model extends Emitter<ModelEvent> { | |||||||
| 
 | 
 | ||||||
|     public getObjectById(id: ObjectID): CtrlObject | undefined { |     public getObjectById(id: ObjectID): CtrlObject | undefined { | ||||||
|         for (let i = 0; i < this.objectPool.length; i++) { |         for (let i = 0; i < this.objectPool.length; i++) { | ||||||
|             if (this.objectPool[i].id.toString() === id.toString()) { |             if (this.objectPool[i].id === id) { | ||||||
|                 return this.objectPool[i]; |                 return this.objectPool[i]; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -8,7 +8,7 @@ class Range extends CtrlObject { | |||||||
|     /** |     /** | ||||||
|      * 坐标 |      * 坐标 | ||||||
|      */ |      */ | ||||||
|     public position: number[] = [0, 0, 0]; |     public position: number[] = []; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * 半径 |      * 半径 | ||||||
|  | |||||||
| @ -35,7 +35,7 @@ class SimulatorWeb extends Component { | |||||||
|         // TODO: 这里要读取存档
 |         // TODO: 这里要读取存档
 | ||||||
|         this.status = new Status(); |         this.status = new Status(); | ||||||
|         this.status.renderer = new ClassicRenderer({ className: "canvas" }).onLoad(); |         this.status.renderer = new ClassicRenderer({ className: "canvas" }).onLoad(); | ||||||
|         this.status.bindRenderer(this.status.renderer); |         this.status.model.bindRenderer(this.status.renderer); | ||||||
|         this.status.setting = this.setting; |         this.status.setting = this.setting; | ||||||
| 
 | 
 | ||||||
|         // 测试代码
 |         // 测试代码
 | ||||||
| @ -75,7 +75,8 @@ class SimulatorWeb extends Component { | |||||||
|                     items: [{ |                     items: [{ | ||||||
|                         panles: ["ObjectList", "Test tab"] |                         panles: ["ObjectList", "Test tab"] | ||||||
|                     }, { |                     }, { | ||||||
|                         panles: ["RangeDetails", "Label e"] |                         items: [{panles: ["Label e", "ee"]}, {panles: ["F"]}], | ||||||
|  |                         layout: LayoutDirection.Y | ||||||
|                     }], |                     }], | ||||||
|                     layout: LayoutDirection.Y |                     layout: LayoutDirection.Y | ||||||
|                 } |                 } | ||||||
|  | |||||||
| @ -41,6 +41,7 @@ class ObjectCommand extends Component<IMixinStatusProps> { | |||||||
| 				className="command-item" | 				className="command-item" | ||||||
| 				onClick={() => { | 				onClick={() => { | ||||||
| 					this.props.status ? this.props.status.newGroup() : undefined; | 					this.props.status ? this.props.status.newGroup() : undefined; | ||||||
|  | 					this.props.status ? this.props.status.model.draw() : undefined; | ||||||
| 				}} | 				}} | ||||||
| 			> | 			> | ||||||
| 				<Icon iconName="WebAppBuilderFragmentCreate"></Icon> | 				<Icon iconName="WebAppBuilderFragmentCreate"></Icon> | ||||||
| @ -49,6 +50,7 @@ class ObjectCommand extends Component<IMixinStatusProps> { | |||||||
| 				className="command-item" | 				className="command-item" | ||||||
| 				onClick={() => { | 				onClick={() => { | ||||||
| 					this.props.status ? this.props.status.newRange() : undefined; | 					this.props.status ? this.props.status.newRange() : undefined; | ||||||
|  | 					this.props.status ? this.props.status.model.draw() : undefined; | ||||||
| 				}} | 				}} | ||||||
| 			> | 			> | ||||||
| 				<Icon iconName="CubeShape"></Icon> | 				<Icon iconName="CubeShape"></Icon> | ||||||
| @ -63,6 +65,7 @@ class ObjectCommand extends Component<IMixinStatusProps> { | |||||||
| 						}) | 						}) | ||||||
| 						this.props.status.model.deleteObject(deleteId); | 						this.props.status.model.deleteObject(deleteId); | ||||||
| 						this.props.status.setFocusObject(new Set<ObjectID>()); | 						this.props.status.setFocusObject(new Set<ObjectID>()); | ||||||
|  | 						this.props.status.model.draw(); | ||||||
| 					} | 					} | ||||||
| 				}} | 				}} | ||||||
| 			> | 			> | ||||||
|  | |||||||
| @ -22,7 +22,6 @@ div.object-list-command-bar { | |||||||
|         width: 30px; |         width: 30px; | ||||||
|         height: 100%; |         height: 100%; | ||||||
|         display: flex; |         display: flex; | ||||||
|         flex-shrink: 0; |  | ||||||
|         justify-content: center; |         justify-content: center; | ||||||
|         align-items: center; |         align-items: center; | ||||||
|         user-select: none; |         user-select: none; | ||||||
|  | |||||||
| @ -1,15 +1,33 @@ | |||||||
| import { Component, ReactNode } from "react"; | import { Component, ReactNode } from "react"; | ||||||
| import { DetailsList } from "@Component/DetailsList/DetailsList"; | import { DetailsList } from "@Component/DetailsList/DetailsList"; | ||||||
| import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status"; | import { useStatus, IMixinStatusProps } from "@Context/Status"; | ||||||
| import { useSetting, IMixinSettingProps } from "@Context/Setting"; | import { useSetting, IMixinSettingProps } from "@Context/Setting"; | ||||||
| import { Localization } from "@Component/Localization/Localization"; | import { Localization } from "@Component/Localization/Localization"; | ||||||
| import { ObjectID } from "@Model/Renderer"; | import { ObjectID } from "@Model/Renderer"; | ||||||
| import "./ObjectList.scss"; | import "./ObjectList.scss"; | ||||||
| 
 | 
 | ||||||
| @useSetting | @useSetting | ||||||
| @useStatusWithEvent("objectChange", "focusObjectChange", "rangeAttrChange") | @useStatus | ||||||
| class ObjectList extends Component<IMixinStatusProps & IMixinSettingProps> { | class ObjectList extends Component<IMixinStatusProps & IMixinSettingProps> { | ||||||
| 
 | 
 | ||||||
|  |     private handelChange = () => { | ||||||
|  |         this.forceUpdate(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public componentDidMount(){ | ||||||
|  |         if (this.props.status) { | ||||||
|  |             this.props.status.model.on("objectChange", this.handelChange); | ||||||
|  |             this.props.status.on("focusObjectChange", this.handelChange); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public componentWillUnmount(){ | ||||||
|  |         if (this.props.status) { | ||||||
|  |             this.props.status.model.off("objectChange", this.handelChange); | ||||||
|  |             this.props.status.off("focusObjectChange", this.handelChange); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     private renderList() { |     private renderList() { | ||||||
|         const objList = this.props.status?.model.objectPool ?? []; |         const objList = this.props.status?.model.objectPool ?? []; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -4,7 +4,6 @@ import { Localization } from "@Component/Localization/Localization"; | |||||||
| import { RenderView } from "./RenderView/RenderView"; | import { RenderView } from "./RenderView/RenderView"; | ||||||
| import { ObjectList } from "./ObjectList/ObjectList"; | import { ObjectList } from "./ObjectList/ObjectList"; | ||||||
| import { ObjectCommand } from "./ObjectList/ObjectCommand"; | import { ObjectCommand } from "./ObjectList/ObjectCommand"; | ||||||
| import { RangeDetails } from "./RangeDetails/RangeDetails"; |  | ||||||
| 
 | 
 | ||||||
| interface IPanelInfo { | interface IPanelInfo { | ||||||
| 	nameKey: string; | 	nameKey: string; | ||||||
| @ -20,7 +19,6 @@ interface IPanelInfo { | |||||||
| type PanelId = "" | type PanelId = "" | ||||||
| | "RenderView" // 主渲染器
 | | "RenderView" // 主渲染器
 | ||||||
| | "ObjectList" // 对象列表
 | | "ObjectList" // 对象列表
 | ||||||
| | "RangeDetails" // 范围属性
 |  | ||||||
| ; | ; | ||||||
| 
 | 
 | ||||||
| const PanelInfoMap = new Map<PanelId, IPanelInfo>(); | const PanelInfoMap = new Map<PanelId, IPanelInfo>(); | ||||||
| @ -32,10 +30,6 @@ PanelInfoMap.set("ObjectList", { | |||||||
|     nameKey: "Panel.Title.Object.List.View", introKay: "Panel.Info.Object.List.View", |     nameKey: "Panel.Title.Object.List.View", introKay: "Panel.Info.Object.List.View", | ||||||
|     class: ObjectList, header: ObjectCommand, hidePadding: true |     class: ObjectList, header: ObjectCommand, hidePadding: true | ||||||
| }) | }) | ||||||
| PanelInfoMap.set("RangeDetails", { |  | ||||||
|     nameKey: "Panel.Title.Range.Details.View", introKay: "Panel.Info.Range.Details.View", |  | ||||||
|     class: RangeDetails |  | ||||||
| }) |  | ||||||
| 
 | 
 | ||||||
| function getPanelById(panelId: PanelId): ReactNode { | function getPanelById(panelId: PanelId): ReactNode { | ||||||
| 	switch (panelId) { | 	switch (panelId) { | ||||||
|  | |||||||
| @ -1,96 +0,0 @@ | |||||||
| import { Component, ReactNode } from "react"; |  | ||||||
| import { AttrInput } from "@Component/AttrInput/AttrInput"; |  | ||||||
| import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status"; |  | ||||||
| import { AllI18nKeys } from "@Component/Localization/Localization"; |  | ||||||
| import { Range } from "@Model/Range"; |  | ||||||
| import { ObjectID } from "@Model/Renderer"; |  | ||||||
| import "./RangeDetails.scss"; |  | ||||||
| 
 |  | ||||||
| @useStatusWithEvent("rangeAttrChange", "focusObjectChange") |  | ||||||
| class RangeDetails extends Component<IMixinStatusProps> { |  | ||||||
| 
 |  | ||||||
|     private renderErrorFrom(error: AllI18nKeys) { |  | ||||||
|         return <> |  | ||||||
| 			<AttrInput keyI18n="Common.Attr.Key.Display.Name" disable disableI18n={error}/> |  | ||||||
| 			<AttrInput keyI18n="Common.Attr.Key.Position.X" disable disableI18n={error}/> |  | ||||||
|             <AttrInput keyI18n="Common.Attr.Key.Position.Y" disable disableI18n={error}/> |  | ||||||
|             <AttrInput keyI18n="Common.Attr.Key.Position.Z" disable disableI18n={error}/> |  | ||||||
| 		</> |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private renderFrom(range: Range) { |  | ||||||
|         return <> |  | ||||||
| 			<AttrInput |  | ||||||
|                 id={range.id} |  | ||||||
|                 keyI18n="Common.Attr.Key.Display.Name" |  | ||||||
|                 value={range.displayName} |  | ||||||
|                 valueChange={(e) => { |  | ||||||
|                     this.props.status ? this.props.status.changeRangeAttrib(range.id, "displayName", e) : null; |  | ||||||
|                 }} |  | ||||||
|             /> |  | ||||||
| 			<AttrInput |  | ||||||
|                 id={range.id} |  | ||||||
|                 isNumber={true} |  | ||||||
|                 step={.1} |  | ||||||
|                 keyI18n="Common.Attr.Key.Position.X" |  | ||||||
|                 value={range.position[0]} |  | ||||||
|                 valueChange={(e) => { |  | ||||||
|                     if (this.props.status) { |  | ||||||
|                         range.position[0] = (e as any) / 1; |  | ||||||
|                         this.props.status.changeRangeAttrib(range.id, "position", range.position); |  | ||||||
|                     } |  | ||||||
|                 }} |  | ||||||
|             /> |  | ||||||
|             <AttrInput |  | ||||||
|                 id={range.id} |  | ||||||
|                 isNumber={true} |  | ||||||
|                 step={.1} |  | ||||||
|                 keyI18n="Common.Attr.Key.Position.Y" |  | ||||||
|                 value={range.position[1]} |  | ||||||
|                 valueChange={(e) => { |  | ||||||
|                     if (this.props.status) { |  | ||||||
|                         range.position[1] = (e as any) / 1; |  | ||||||
|                         this.props.status.changeRangeAttrib(range.id, "position", range.position); |  | ||||||
|                     } |  | ||||||
|                 }} |  | ||||||
|             /> |  | ||||||
|             <AttrInput |  | ||||||
|                 id={range.id} |  | ||||||
|                 isNumber={true} |  | ||||||
|                 step={.1} |  | ||||||
|                 keyI18n="Common.Attr.Key.Position.Z" |  | ||||||
|                 value={range.position[2]} |  | ||||||
|                 valueChange={(e) => { |  | ||||||
|                     if (this.props.status) { |  | ||||||
|                         range.position[2] = (e as any) / 1; |  | ||||||
|                         this.props.status.changeRangeAttrib(range.id, "position", range.position); |  | ||||||
|                     } |  | ||||||
|                 }} |  | ||||||
|             /> |  | ||||||
| 		</> |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| 	public render(): ReactNode { |  | ||||||
|         if (this.props.status) { |  | ||||||
|             if (this.props.status.focusObject.size <= 0) { |  | ||||||
|                 return this.renderErrorFrom("Panel.Info.Range.Details.Attr.Error.Unspecified"); |  | ||||||
|             } |  | ||||||
|             if (this.props.status.focusObject.size > 1) { |  | ||||||
|                 return this.renderErrorFrom("Common.Attr.Key.Error.Multiple"); |  | ||||||
|             } |  | ||||||
|             let id: ObjectID = 0; |  | ||||||
|             this.props.status.focusObject.forEach((cid => id = cid)); |  | ||||||
|              |  | ||||||
|             let range = this.props.status!.model.getObjectById(id); |  | ||||||
| 
 |  | ||||||
|             if (range instanceof Range) { |  | ||||||
|                 return this.renderFrom(range); |  | ||||||
|             } else { |  | ||||||
|                 return this.renderErrorFrom("Panel.Info.Range.Details.Attr.Error.Not.Range"); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 		return this.renderErrorFrom("Panel.Info.Range.Details.Attr.Error.Unspecified"); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export { RangeDetails }; |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user