diff --git a/.drone.yml b/.drone.yml index 7e28fe7..9d0ee01 100644 --- a/.drone.yml +++ b/.drone.yml @@ -19,9 +19,9 @@ steps: commands: - npm config set registry https://registry.npm.taobao.org - npm ci - - npm run release-lab - - rm -rf ./build_lab/* - - cp ./build/* ./build_lab +# - npm run release-lab +# - rm -rf ./build_lab/* +# - cp ./build/* ./build_lab - npm run release-web - rm -rf ./build_web/* - cp ./build/* ./build_web diff --git a/source/Component/LabelList/LabelList.scss b/source/Component/LabelList/LabelList.scss index 3964103..fb58a26 100644 --- a/source/Component/LabelList/LabelList.scss +++ b/source/Component/LabelList/LabelList.scss @@ -38,6 +38,7 @@ div.label { } div.dark.label { + transition: none; background-color: $lt-bg-color-lvl3-dark; div.label-color { @@ -45,12 +46,12 @@ div.dark.label { } div.delete-button:hover { - color: $lt-font-color-lvl2-dark; - background-color: $lt-bg-color-lvl2-dark; + color: $lt-red; } } div.light.label { + transition: none; background-color: $lt-bg-color-lvl3-light; div.label-color { @@ -58,7 +59,18 @@ div.light.label { } div.delete-button:hover { - color: $lt-font-color-lvl2-light; - background-color: $lt-bg-color-lvl2-light; + color: $lt-red; } +} + +div.dark.label:hover, +div.dark.label.focus { + color: $lt-font-color-lvl2-dark; + background-color: $lt-bg-color-lvl2-dark; +} + +div.light.label:hover, +div.light.label.focus { + color: $lt-font-color-lvl2-light; + background-color: $lt-bg-color-lvl2-light; } \ No newline at end of file diff --git a/source/Component/LabelList/LabelList.tsx b/source/Component/LabelList/LabelList.tsx index 01ca9cf..59eba50 100644 --- a/source/Component/LabelList/LabelList.tsx +++ b/source/Component/LabelList/LabelList.tsx @@ -2,54 +2,82 @@ import { Component } 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 { labels: Label[]; canDelete?: boolean; -} - -interface ILabelListState { focusLabel?: Label; + clickLabel?: (label: Label) => any; + deleteLabel?: (label: Label) => any; } @useSetting -class LabelList extends Component { - - public state: Readonly = { - focusLabel: undefined - }; +class LabelList extends Component { + + private isDeleteClick: boolean = false; private renderLabel(label: Label) { const theme = this.props.setting?.themes ?? Themes.dark; - const themeClassName = theme === Themes.dark ? "dark" : "light"; + const classList:string[] = ["label"]; + classList.push( theme === Themes.dark ? "dark" : "light" ); + const isFocus = this.props.focusLabel && this.props.focusLabel.equal(label); + if (isFocus) { + classList.push("focus"); + } const colorCss = `rgb(${label.color.join(",")})`; - return
+ return
{ + if (this.props.clickLabel && !this.isDeleteClick) { + this.props.clickLabel(label); + } + this.isDeleteClick = false; + }} + style={{ + borderColor: isFocus ? colorCss : undefined + }} + >
{label.name}
{ this.props.canDelete ? -
+
{ + this.isDeleteClick = true; + if (this.props.deleteLabel) { + this.props.deleteLabel(label); + } + }} + >
: null }
} + + private renderAllLabels(labels: Label[]) { + return this.props.labels.map((label) => { + return this.renderLabel(label); + }); + } public render() { - return <> - { - this.props.labels.map((label) => { - return this.renderLabel(label); - }) - } - + if (this.props.labels.length > 0) { + return this.renderAllLabels(this.props.labels); + } else { + return + } } } diff --git a/source/Context/Status.tsx b/source/Context/Status.tsx index 8573ecd..957e196 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 { Label } from "@Model/Label"; import { Range } from "@Model/Range"; import { Archive } from "@Model/Archive"; import { AbstractRenderer } from "@Model/Renderer"; @@ -27,6 +28,7 @@ interface IStatusEvent { physicsLoop: number; mouseModChange: void; focusObjectChange: void; + focusLabelChange: void; objectChange: void; labelChange: void; rangeAttrChange: void; @@ -62,6 +64,11 @@ class Status extends Emitter { */ public focusObject: Set = new Set(); + /** + * 焦点标签 + */ + public focusLabel?: Label; + public constructor() { super(); @@ -92,6 +99,14 @@ class Status extends Emitter { this.emit("focusObjectChange"); } + /** + * 更新焦点标签 + */ + public setLabelObject(focusLabel?: Label) { + this.focusLabel = focusLabel; + this.emit("focusLabelChange"); + } + /** * 修改范围属性 */ diff --git a/source/Localization/EN-US.ts b/source/Localization/EN-US.ts index 39225ae..9253e47 100644 --- a/source/Localization/EN-US.ts +++ b/source/Localization/EN-US.ts @@ -36,7 +36,9 @@ const EN_US = { "Panel.Title.Range.Details.View": "Range attributes", "Panel.Info.Range.Details.View": "Edit view range attributes", "Panel.Title.Label.List.View": "Label list", - "Panel.Info.Label.List.View": "Edit view label attributes", + "Panel.Info.Label.List.View": "Edit view label list", + "Panel.Title.Label.Details.View": "Label attributes", + "Panel.Info.Label.Details.View": "Edit view label attributes", "Common.Attr.Key.Display.Name": "Display name", "Common.Attr.Key.Position.X": "Position X", "Common.Attr.Key.Position.Y": "Position Y", @@ -50,5 +52,7 @@ const EN_US = { "Common.Attr.Key.Error.Multiple": "Multiple values", "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.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", } 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 1aad911..7986b9e 100644 --- a/source/Localization/ZH-CN.ts +++ b/source/Localization/ZH-CN.ts @@ -32,11 +32,13 @@ const ZH_CN = { "Panel.Title.Render.View": "实时预览", "Panel.Info.Render.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": "编辑查看范围属性", "Panel.Title.Label.List.View": "标签列表", - "Panel.Info.Label.List.View": "编辑查看标签属性", + "Panel.Info.Label.List.View": "编辑查看标签列表", + "Panel.Title.Label.Details.View": "标签属性", + "Panel.Info.Label.Details.View": "编辑查看标签属性", "Common.Attr.Key.Display.Name": "显示名称", "Common.Attr.Key.Position.X": "X 坐标", "Common.Attr.Key.Position.Y": "Y 坐标", @@ -50,5 +52,7 @@ const ZH_CN = { "Common.Attr.Key.Error.Multiple": "多重数值", "Panel.Info.Range.Details.Attr.Error.Not.Range": "对象不是一个范围", "Panel.Info.Range.Details.Attr.Error.Unspecified": "未指定范围对象", + "Panel.Info.Label.Details.Error.Unspecified": "未指定标签对象", + "Panel.Info.Label.List.Error.Nodata": "模型中没有标签,点击按钮以创建", } export default ZH_CN; \ No newline at end of file diff --git a/source/Page/SimulatorWeb/SimulatorWeb.tsx b/source/Page/SimulatorWeb/SimulatorWeb.tsx index 952dcbd..7c18c26 100644 --- a/source/Page/SimulatorWeb/SimulatorWeb.tsx +++ b/source/Page/SimulatorWeb/SimulatorWeb.tsx @@ -77,7 +77,7 @@ class SimulatorWeb extends Component { items: [{ panels: ["ObjectList", "Test tab"] }, { - panels: ["RangeDetails", "Label e"] + panels: ["RangeDetails", "LabelDetails"] }], layout: LayoutDirection.Y } diff --git a/source/Panel/LabelDetails/LabelDetails.scss b/source/Panel/LabelDetails/LabelDetails.scss new file mode 100644 index 0000000..e69de29 diff --git a/source/Panel/LabelDetails/LabelDetails.tsx b/source/Panel/LabelDetails/LabelDetails.tsx new file mode 100644 index 0000000..118a2df --- /dev/null +++ b/source/Panel/LabelDetails/LabelDetails.tsx @@ -0,0 +1,54 @@ +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 { ColorInput } from "@Component/ColorInput/ColorInput"; +import "./LabelDetails.scss"; +import { LabelList } from "@Component/LabelList/LabelList"; +import { Label } from "@Model/Label"; + +@useStatusWithEvent("focusLabelChange") +class LabelDetails extends Component { + + public readonly AttrI18nKey: AllI18nKeys[] = [ + "Common.Attr.Key.Display.Name", + "Common.Attr.Key.Color", + ] + + private renderFrom(label: Label) { + return <> + + { + if (this.props.status) { + this.props.status.model.deleteLabel(label); + this.props.status.setLabelObject(); + } + }} + /> + + + + { + if (this.props.status) { + + } + }}/> + + ; + } + + public render(): ReactNode { + if (this.props.status) { + if (this.props.status.focusLabel) { + return this.renderFrom(this.props.status.focusLabel); + } + } + return ; + } +} + +export { LabelDetails }; \ No newline at end of file diff --git a/source/Panel/LabelList/LabelList.scss b/source/Panel/LabelList/LabelList.scss index 179597e..b9eec31 100644 --- a/source/Panel/LabelList/LabelList.scss +++ b/source/Panel/LabelList/LabelList.scss @@ -1,33 +1,8 @@ @import "../../Component/Theme/Theme.scss"; -div.label-list-command-bar { +div.label-list-panel-root { width: 100%; - height: 30px; - flex-shrink: 0; - display: flex; - - div.command-item { - width: 30px; - height: 100%; - display: flex; - flex-shrink: 0; - justify-content: center; - align-items: center; - user-select: none; - cursor: pointer; - } -} - -div.dark.label-list-command-bar { - - div.command-item:hover { - background-color: $lt-bg-color-lvl3-dark; - } -} - -div.light.label-list-command-bar { - - div.command-item:hover { - background-color: $lt-bg-color-lvl3-light; - } + height: 100%; + padding: 10px; + box-sizing: border-box; } \ No newline at end of file diff --git a/source/Panel/LabelList/LabelList.tsx b/source/Panel/LabelList/LabelList.tsx index 07908b8..bb41ae5 100644 --- a/source/Panel/LabelList/LabelList.tsx +++ b/source/Panel/LabelList/LabelList.tsx @@ -1,7 +1,7 @@ -import { Theme } from "@Component/Theme/Theme"; import { LabelList as LabelListComponent } from "@Component/LabelList/LabelList"; import { Component } from "react"; import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status"; +import { useSetting, IMixinSettingProps } from "@Context/Setting"; import { Label } from "@Model/Label"; import "./LabelList.scss"; @@ -9,15 +9,48 @@ interface ILabelListProps { } -@useStatusWithEvent("labelChange") -class LabelList extends Component { +@useSetting +@useStatusWithEvent("labelChange", "focusLabelChange") +class LabelList extends Component { + private labelInnerClick: boolean = false; + public render() { let labels: Label[] = []; if (this.props.status) { labels = this.props.status.model.labelPool.concat([]); } - return + return
{ + if (this.props.status && !this.labelInnerClick) { + this.props.status.setLabelObject(); + } + this.labelInnerClick = false; + }} + > + { + if (this.props.status) { + this.props.status.setLabelObject(label); + } + if (this.props.setting) { + this.props.setting.layout.focus("LabelDetails"); + } + this.labelInnerClick = true; + }} + deleteLabel={(label) => { + if (this.props.status) { + this.props.status.model.deleteLabel(label); + this.props.status.setLabelObject(); + } + this.labelInnerClick = true; + }} + /> +
; } } diff --git a/source/Panel/ObjectList/ObjectList.tsx b/source/Panel/ObjectList/ObjectList.tsx index fbbee28..117a571 100644 --- a/source/Panel/ObjectList/ObjectList.tsx +++ b/source/Panel/ObjectList/ObjectList.tsx @@ -36,12 +36,15 @@ class ObjectList extends Component { } }))} clickLine={(item) => { - if (this.props.setting) { - this.props.setting.layout.focus("ObjectList"); - } if (this.props.status) { this.props.status.setFocusObject(new Set().add(item.key)); } + if (this.props.setting) { + if (item.key.slice(0, 1) === "R") { + this.props.setting.layout.focus("RangeDetails"); + } + this.props.setting.layout.focus("ObjectList"); + } }} checkBox={(item) => { if (this.props.setting) { diff --git a/source/Panel/Panel.tsx b/source/Panel/Panel.tsx index 747d4cd..7598f9a 100644 --- a/source/Panel/Panel.tsx +++ b/source/Panel/Panel.tsx @@ -6,6 +6,7 @@ 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"; interface IPanelInfo { nameKey: string; @@ -23,6 +24,7 @@ type PanelId = "" | "ObjectList" // 对象列表 | "RangeDetails" // 范围属性 | "LabelList" // 标签列表 +| "LabelDetails" // 标签属性 ; const PanelInfoMap = new Map(); @@ -40,7 +42,11 @@ PanelInfoMap.set("RangeDetails", { }) PanelInfoMap.set("LabelList", { nameKey: "Panel.Title.Label.List.View", introKay: "Panel.Info.Label.List.View", - class: LabelList + class: LabelList, hidePadding: true +}) +PanelInfoMap.set("LabelDetails", { + nameKey: "Panel.Title.Label.Details.View", introKay: "Panel.Info.Label.Details.View", + class: LabelDetails }) function getPanelById(panelId: PanelId): ReactNode {