From f3ba3b61507bef0f92525fcdd9892eaa63f89939 Mon Sep 17 00:00:00 2001 From: MrKBear Date: Mon, 7 Mar 2022 17:47:55 +0800 Subject: [PATCH] Add Attrinput component --- source/Component/AttrInput/AttrInput.scss | 1 + source/Component/AttrInput/AttrInput.tsx | 120 +++++++++++---------- source/Context/Status.tsx | 15 +++ source/Localization/EN-US.ts | 3 + source/Localization/ZH-CN.ts | 3 + source/Model/Model.ts | 2 +- source/Model/Range.ts | 2 +- source/Panel/ObjectList/ObjectList.tsx | 2 +- source/Panel/RangeDetails/RangeDetails.tsx | 80 ++++++++++++-- 9 files changed, 162 insertions(+), 66 deletions(-) diff --git a/source/Component/AttrInput/AttrInput.scss b/source/Component/AttrInput/AttrInput.scss index ce1cd82..78678d7 100644 --- a/source/Component/AttrInput/AttrInput.scss +++ b/source/Component/AttrInput/AttrInput.scss @@ -66,6 +66,7 @@ div.attr-input { div.err-message { color: $lt-red; padding-top: 5px; + min-height: 24px; } } } diff --git a/source/Component/AttrInput/AttrInput.tsx b/source/Component/AttrInput/AttrInput.tsx index 633bc06..fba16e8 100644 --- a/source/Component/AttrInput/AttrInput.tsx +++ b/source/Component/AttrInput/AttrInput.tsx @@ -13,24 +13,15 @@ interface IAttrInputProps { max?: number; min?: number; step?: number; + disable?: boolean; + disableI18n?: AllI18nKeys; valueChange?: (value: this["isNumber"] extends true ? number : string) => any; } -interface AttrInputState { - error: ReactNode; - value: string; -} +class AttrInput extends Component { -class AttrInput extends Component { - - public constructor(props: IAttrInputProps) { - super(props); - const value = props.value ?? props.isNumber ? "0" : ""; - this.state = { - error: this.check(value), - value: value - } - } + private value: string = ""; + private error: ReactNode; private check(value: string): ReactNode { @@ -63,16 +54,17 @@ class AttrInput extends Component { } private handelValueChange = () => { - if (!this.state.error && this.props.valueChange) { - this.props.valueChange(this.state.value); + if (!this.error && this.props.valueChange) { + this.props.valueChange(this.value); } + this.forceUpdate(); } private changeValue = (direction: number) => { - if (this.state.error) { + if (this.error) { return; } else { - let newVal = (this.state.value as any / 1) + (this.props.step ?? 1) * direction; + let newVal = (this.value as any / 1) + (this.props.step ?? 1) * direction; // 最大值校验 if (this.props.max !== undefined && newVal > this.props.max) { @@ -84,15 +76,60 @@ class AttrInput extends Component { newVal = this.props.min; } - this.setState( - { value: newVal.toString() }, - () => this.handelValueChange() - ); + this.value = newVal.toString(); + this.handelValueChange() } } + private renderInput() { + return <> +
+ { + this.props.isNumber ?
this.changeValue(-1)} + > + +
: null + } + { + this.value = e.target.value; + this.error = this.check(e.target.value); + this.handelValueChange(); + }} + > + { + this.props.isNumber ?
this.changeValue(1)} + > + +
: null + } +
+ { + this.error ? +
+ {this.error} +
: null + } + + } + public render(): ReactNode { + if (!this.error) { + const value = this.props.value ?? (this.props.isNumber ? "0" : ""); + this.value = value.toString(); + this.error = this.check(value.toString()); + } + return {
-
- { - this.props.isNumber ?
this.changeValue(-1)} - > - -
: null - } - { - this.setState({ - error: this.check(e.target.value), - value: e.target.value - }, () => this.handelValueChange()); - }} - > - { - this.props.isNumber ?
this.changeValue(1)} - > - -
: null - } -
{ -
- {this.state.error} -
+ this.props.disable ? + this.props.disableI18n ? + : +
{this.props.value}
: + this.renderInput() }
diff --git a/source/Context/Status.tsx b/source/Context/Status.tsx index 3289c69..81cbdcc 100644 --- a/source/Context/Status.tsx +++ b/source/Context/Status.tsx @@ -1,6 +1,7 @@ import { createContext, Component, FunctionComponent, useState, useEffect, ReactNode } from "react"; import { Emitter } from "@Model/Emitter"; import { Model, ObjectID } from "@Model/Model"; +import { Range } from "@Model/Range"; import { Archive } from "@Model/Archive"; import { AbstractRenderer } from "@Model/Renderer"; import { ClassicRenderer, MouseMod } from "@GLRender/ClassicRenderer"; @@ -22,6 +23,7 @@ interface IStatusEvent { focusObjectChange: void; objectChange: void; labelChange: void; + rangeAttrChange: void; } class Status extends Emitter { @@ -83,6 +85,19 @@ class Status extends Emitter { this.emit("focusObjectChange"); } + /** + * 修改范围属性 + */ + public changeRangeAttrib + (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(); + } + } + /** * 鼠标工具状态 */ diff --git a/source/Localization/EN-US.ts b/source/Localization/EN-US.ts index dc506d9..6211a6d 100644 --- a/source/Localization/EN-US.ts +++ b/source/Localization/EN-US.ts @@ -38,5 +38,8 @@ const EN_US = { "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; \ No newline at end of file diff --git a/source/Localization/ZH-CN.ts b/source/Localization/ZH-CN.ts index 7e6f645..bed66b3 100644 --- a/source/Localization/ZH-CN.ts +++ b/source/Localization/ZH-CN.ts @@ -38,5 +38,8 @@ const ZH_CN = { "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; \ No newline at end of file diff --git a/source/Model/Model.ts b/source/Model/Model.ts index 95fd3c8..cda7ccb 100644 --- a/source/Model/Model.ts +++ b/source/Model/Model.ts @@ -39,7 +39,7 @@ class Model extends Emitter { public getObjectById(id: ObjectID): CtrlObject | undefined { for (let i = 0; i < this.objectPool.length; i++) { - if (this.objectPool[i].id === id) { + if (this.objectPool[i].id.toString() === id.toString()) { return this.objectPool[i]; } } diff --git a/source/Model/Range.ts b/source/Model/Range.ts index 6177d68..5e7c1f3 100644 --- a/source/Model/Range.ts +++ b/source/Model/Range.ts @@ -8,7 +8,7 @@ class Range extends CtrlObject { /** * 坐标 */ - public position: number[] = []; + public position: number[] = [0, 0, 0]; /** * 半径 diff --git a/source/Panel/ObjectList/ObjectList.tsx b/source/Panel/ObjectList/ObjectList.tsx index 5d6fc7e..fbbee28 100644 --- a/source/Panel/ObjectList/ObjectList.tsx +++ b/source/Panel/ObjectList/ObjectList.tsx @@ -7,7 +7,7 @@ import { ObjectID } from "@Model/Renderer"; import "./ObjectList.scss"; @useSetting -@useStatusWithEvent("objectChange", "focusObjectChange") +@useStatusWithEvent("objectChange", "focusObjectChange", "rangeAttrChange") class ObjectList extends Component { private renderList() { diff --git a/source/Panel/RangeDetails/RangeDetails.tsx b/source/Panel/RangeDetails/RangeDetails.tsx index 52cf4b7..57d2e34 100644 --- a/source/Panel/RangeDetails/RangeDetails.tsx +++ b/source/Panel/RangeDetails/RangeDetails.tsx @@ -1,15 +1,81 @@ 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"; -class RangeDetails extends Component { +@useStatusWithEvent("rangeAttrChange", "focusObjectChange") +class RangeDetails extends Component { + + private renderErrorFrom(error: AllI18nKeys) { + return <> + + + + + + } + + private renderFrom(range: Range) { + return <> + { + this.props.status ? this.props.status.changeRangeAttrib(range.id, "displayName", e) : null; + }} + /> + { + if (this.props.status) { + range.position[0] = (e as any) / 1; + this.props.status.changeRangeAttrib(range.id, "position", range.position); + } + }} + /> + { + this.props.status ? this.props.status.changeRangeAttrib(range.id, "displayName", e) : null; + }} + /> + { + this.props.status ? this.props.status.changeRangeAttrib(range.id, "displayName", e) : null; + }} + /> + + } + public render(): ReactNode { - return
- - - - -
+ 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"); } }