Add group list panel #20
@ -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", () => {
|
||||
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) => {
|
||||
<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) => {
|
||||
<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) => {
|
||||
<TogglesInput
|
||||
keyI18n="Common.Attr.Key.Delete"
|
||||
onIconName="delete" offIconName="delete"
|
||||
valueChange={() => {
|
||||
if (this.props.status) {
|
||||
this.props.status.changeRangeAttrib(range.id, "color", color);
|
||||
this.props.status.model.deleteObject([range]);
|
||||
this.props.status.setFocusObject(new Set());
|
||||
}
|
||||
}}/>
|
||||
}}
|
||||
/>
|
||||
|
||||
{this.renderAttrInput(range.id, keyIndex ++, range.position[0], (val, status) => {
|
||||
<Message i18nKey="Common.Attr.Title.Spatial" isTitle/>
|
||||
|
||||
{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, keyIndex ++, range.position[1], (val, status) => {
|
||||
}, .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, keyIndex ++, range.position[2], (val, status) => {
|
||||
}, .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)}
|
||||
}, .1
|
||||
)}
|
||||
|
||||
{this.renderAttrInput(range.id, keyIndex ++, range.radius[0], (val, status) => {
|
||||
{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, keyIndex ++, range.radius[1], (val, status) => {
|
||||
}, .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, keyIndex ++, range.radius[2], (val, status) => {
|
||||
}, .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)}
|
||||
}, .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