From 86c840443c84925002f55598d129c056b92cbadf Mon Sep 17 00:00:00 2001 From: MrKBear Date: Sat, 5 Mar 2022 11:37:35 +0800 Subject: [PATCH 1/2] Add checkbox handel func --- source/Component/DetailsList/DetailsList.scss | 31 +++++++++++++++-- source/Component/DetailsList/DetailsList.tsx | 30 ++++++++++++++-- source/Context/Status.tsx | 19 +++++++++-- source/Model/Model.ts | 8 +++++ source/Page/SimulatorWeb/SimulatorWeb.tsx | 2 +- source/Panel/ObjectList/ObjectList.scss | 4 +++ source/Panel/ObjectList/ObjectList.tsx | 34 ++++++++++++++++++- source/Panel/RenderView/RenderView.tsx | 2 +- 8 files changed, 120 insertions(+), 10 deletions(-) diff --git a/source/Component/DetailsList/DetailsList.scss b/source/Component/DetailsList/DetailsList.scss index 011913f..bb9ea24 100644 --- a/source/Component/DetailsList/DetailsList.scss +++ b/source/Component/DetailsList/DetailsList.scss @@ -19,9 +19,18 @@ div.details-list { div.details-list-checkbox { display: flex; + width: 30px; align-items: center; justify-content: center; - padding: 0 10px; + opacity: 0; + } + } + + div.details-list-item.active, + div.details-list-item:hover { + + div.details-list-checkbox { + opacity: 1; } } } @@ -35,15 +44,33 @@ div.light.details-list { div.details-list-item:hover { background-color: $lt-bg-color-lvl3-light; } + + div.details-list-item.active { + background-color: $lt-bg-color-lvl2-light; + color: rgba(0, 0, 0, 0.95); + } + + // div.details-list-checkbox:hover { + // background-color: rgba($lt-bg-color-lvl1-light, .4); + // } } div.dark.details-list { div.details-list-item:nth-child(2n) { - background-color: rgba($lt-bg-color-lvl5-dark, .4); + background-color: rgba($lt-bg-color-lvl5-dark, .8); } div.details-list-item:hover { background-color: $lt-bg-color-lvl3-dark; } + + div.details-list-item.active { + background-color: $lt-bg-color-lvl2-dark; + color: rgba(255, 255, 255, 0.85); + } + + // div.details-list-checkbox:hover { + // background-color: rgba($lt-bg-color-lvl1-dark, .8); + // } } \ No newline at end of file diff --git a/source/Component/DetailsList/DetailsList.tsx b/source/Component/DetailsList/DetailsList.tsx index a40eb0d..d50e2ca 100644 --- a/source/Component/DetailsList/DetailsList.tsx +++ b/source/Component/DetailsList/DetailsList.tsx @@ -16,9 +16,13 @@ interface IColumns { interface IDetailsListProps { items: IItems[]; + className?: string; columns: IColumns[]; hideCheckBox?: boolean; checkboxClassName?: string; + click?: () => void; + clickLine?: (item: IItems) => any; + checkBox?: (data: IItems) => any; } class DetailsList extends Component { @@ -41,13 +45,27 @@ class DetailsList extends Component { public render(): ReactNode { return { this.props.items.map((item) => { const { checkboxClassName } = this.props; - return
+ const classList: string[] = ["details-list-item"]; + if (item.select) { + classList.push("active"); + } + return
{ + if (this.props.clickLine) { + e.stopPropagation(); + this.props.clickLine(item); + } + }} + > { this.props.columns.map((column) => { if (column.beforeCheckbox) { @@ -59,6 +77,12 @@ class DetailsList extends Component { this.props.hideCheckBox ? null :
{ + if (this.props.checkBox) { + e.stopPropagation(); + this.props.checkBox(item); + } + }} >
@@ -76,4 +100,4 @@ class DetailsList extends Component { } } -export { DetailsList }; \ No newline at end of file +export { DetailsList, IItems }; \ No newline at end of file diff --git a/source/Context/Status.tsx b/source/Context/Status.tsx index 0920a22..cea98b7 100644 --- a/source/Context/Status.tsx +++ b/source/Context/Status.tsx @@ -1,7 +1,8 @@ import { createContext, Component, FunctionComponent } from "react"; import { Emitter } from "@Model/Emitter"; -import { Model } from "@Model/Model"; +import { Model, ObjectID } from "@Model/Model"; import { Archive } from "@Model/Archive"; +import { CtrlObject } from "@Model/CtrlObject"; import { AbstractRenderer } from "@Model/Renderer"; import { ClassicRenderer, MouseMod } from "@GLRender/ClassicRenderer"; import { Setting } from "./Setting"; @@ -16,7 +17,8 @@ function randomColor() { } class Status extends Emitter<{ - mouseModChange: MouseMod + mouseModChange: MouseMod, + focusObjectChange: Set }> { public setting: Setting = undefined as any; @@ -41,6 +43,19 @@ class Status extends Emitter<{ */ public model: Model = new Model(); + /** + * 焦点对象 + */ + public focusObject: Set = new Set(); + + /** + * 更新焦点对象 + */ + public setFocusObject(focusObject: Set) { + this.focusObject = focusObject; + this.emit("focusObjectChange", this.focusObject); + } + /** * 鼠标工具状态 */ diff --git a/source/Model/Model.ts b/source/Model/Model.ts index 22dcf17..0a4ebb0 100644 --- a/source/Model/Model.ts +++ b/source/Model/Model.ts @@ -37,6 +37,14 @@ class Model extends Emitter { */ public objectPool: CtrlObject[] = []; + public getObjectById(id: ObjectID): CtrlObject | undefined { + for (let i = 0; i < this.objectPool.length; i++) { + if (this.objectPool[i].id === id) { + return this.objectPool[i]; + } + } + } + /** * 标签列表 */ diff --git a/source/Page/SimulatorWeb/SimulatorWeb.tsx b/source/Page/SimulatorWeb/SimulatorWeb.tsx index 72fae27..3c14aa1 100644 --- a/source/Page/SimulatorWeb/SimulatorWeb.tsx +++ b/source/Page/SimulatorWeb/SimulatorWeb.tsx @@ -73,7 +73,7 @@ class SimulatorWeb extends Component { }, { items: [{ - panles: ["ObjectList"] + panles: ["ObjectList", "Test tab"] }, { items: [{panles: ["Label e", "ee"]}, {panles: ["F"]}], layout: LayoutDirection.Y diff --git a/source/Panel/ObjectList/ObjectList.scss b/source/Panel/ObjectList/ObjectList.scss index 9879ba3..1f4cb47 100644 --- a/source/Panel/ObjectList/ObjectList.scss +++ b/source/Panel/ObjectList/ObjectList.scss @@ -4,4 +4,8 @@ div.object-list-color-value { margin-left: 3px; border-radius: 1000px; width: 3px; +} + +div.object-list { + min-height: 100%; } \ No newline at end of file diff --git a/source/Panel/ObjectList/ObjectList.tsx b/source/Panel/ObjectList/ObjectList.tsx index aa0bd8b..7104cb9 100644 --- a/source/Panel/ObjectList/ObjectList.tsx +++ b/source/Panel/ObjectList/ObjectList.tsx @@ -2,6 +2,7 @@ import { Component, ReactNode } from "react"; import { DetailsList } from "@Component/DetailsList/DetailsList"; import { useStatus, IMixinStatusProps } from "@Context/Status"; import { Localization } from "@Component/Localization/Localization"; +import { ObjectID } from "@Model/Renderer"; import "./ObjectList.scss"; @useStatus @@ -14,12 +15,14 @@ class ObjectList extends Component { 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); } } @@ -34,15 +37,44 @@ class ObjectList extends Component { } return { return { key: object.id.toString(), name: object.displayName, color: object.color, display: object.display, - update: object.update + update: object.update, + select: this.props.status ? + this.props.status.focusObject.has(object.id.toString()) || + this.props.status.focusObject.has(object.id) : + false } }))} + clickLine={(item) => { + if (this.props.status) { + this.props.status.setFocusObject(new Set().add(item.key)); + } + }} + checkBox={(item) => { + if (this.props.status) { + if ( + this.props.status.focusObject.has(item.key.toString()) || + this.props.status.focusObject.has(item.key) + ) { + this.props.status.focusObject.delete(item.key); + this.props.status.focusObject.delete(item.key.toString()); + this.props.status.setFocusObject(this.props.status.focusObject); + } else { + this.props.status.setFocusObject(this.props.status.focusObject.add(item.key)); + } + } + }} + click={() => { + if (this.props.status) { + this.props.status.setFocusObject(new Set()); + } + }} columns={[ { key: "color", diff --git a/source/Panel/RenderView/RenderView.tsx b/source/Panel/RenderView/RenderView.tsx index 8bef356..e61c491 100644 --- a/source/Panel/RenderView/RenderView.tsx +++ b/source/Panel/RenderView/RenderView.tsx @@ -28,7 +28,7 @@ class RenderView extends Component { public componentDidMount() { let div = this.rootEle.current; - console.log(div, div?.childNodes, this.props.status, this.props.status?.renderer.dom) + // console.log(div, div?.childNodes, this.props.status, this.props.status?.renderer.dom) if (div && (!div.childNodes || div.childNodes.length <= 0) && this.props.status) { div.appendChild(this.props.status.renderer.dom); } From a684db23068ab331a4b8c0d12fe7df5e9aa0ea01 Mon Sep 17 00:00:00 2001 From: MrKBear Date: Sat, 5 Mar 2022 18:30:32 +0800 Subject: [PATCH 2/2] Add object list command bar --- source/Component/Container/Container.scss | 16 +++- source/Component/Container/Container.tsx | 32 ++++++-- source/Component/DetailsList/DetailsList.scss | 4 +- source/Model/Model.ts | 15 ++-- source/Panel/ObjectList/ObjectCommand.tsx | 78 +++++++++++++++++++ source/Panel/ObjectList/ObjectList.scss | 33 ++++++++ source/Panel/ObjectList/ObjectList.tsx | 10 ++- source/Panel/Panel.tsx | 4 +- 8 files changed, 173 insertions(+), 19 deletions(-) create mode 100644 source/Panel/ObjectList/ObjectCommand.tsx diff --git a/source/Component/Container/Container.scss b/source/Component/Container/Container.scss index 9f2da00..99442d6 100644 --- a/source/Component/Container/Container.scss +++ b/source/Component/Container/Container.scss @@ -6,6 +6,7 @@ div.app-container { width: 100%; height: 100%; display: flex; + align-items: stretch; overflow: hidden; box-sizing: border-box; @@ -98,13 +99,24 @@ div.app-container { padding: 10px; } + div.app-panel-root { + width: 100%; + height: calc( 100% - 32px ); + box-sizing: border-box; + display: flex; + justify-content: space-between; + align-items: stretch; + flex-direction: column; + border: .8px solid rgba($color: #000000, $alpha: 0); + } + div.app-panel { width: 100%; height: 100%; box-sizing: border-box; overflow: scroll; -ms-overflow-style: none; - border: .8px solid rgba($color: #000000, $alpha: 0); + flex-shrink: 1; } div.app-panel.hide-scrollbar::-webkit-scrollbar { @@ -128,7 +140,7 @@ div.app-container { background-color: rgba($color: #000000, $alpha: 0); } - div.app-panel.active { + div.app-panel-root.active { border: .8px solid blue !important; } } diff --git a/source/Component/Container/Container.tsx b/source/Component/Container/Container.tsx index 268b35b..4b8981c 100644 --- a/source/Component/Container/Container.tsx +++ b/source/Component/Container/Container.tsx @@ -68,7 +68,7 @@ class Container extends Component { delay={2} key={panelId} > -
{ e.stopPropagation(); @@ -90,16 +90,32 @@ class Container extends Component { }
: null }
this.props.onFocusTab ? this.props.onFocusTab(showPanelId) : undefined} className={[ - "app-panel", - hasActivePanel ? "active" : "", - showPanelInfo?.hidePadding ? "" : "has-padding", - showPanelInfo?.hideScrollBar ? "hide-scrollbar" : "" + "app-panel-root", + hasActivePanel ? "active" : "" ].filter(x => !!x).join(" ")} - draggable={false} + onClick={() => this.props.onFocusTab ? this.props.onFocusTab(showPanelId) : undefined} > - {getPanelById(showPanelId as any)} + {/* 渲染 Command Bar */} + {(() => { + let info = getPanelInfoById(showPanelId as any); + if (info && info.header) { + const Header = info.header; + return
+ } + })()} + + {/* 渲染 Panel 内容 */} +
!!x).join(" ")} + draggable={false} + > + {getPanelById(showPanelId as any)} +
} diff --git a/source/Component/DetailsList/DetailsList.scss b/source/Component/DetailsList/DetailsList.scss index bb9ea24..c48ebe9 100644 --- a/source/Component/DetailsList/DetailsList.scss +++ b/source/Component/DetailsList/DetailsList.scss @@ -37,7 +37,7 @@ div.details-list { div.light.details-list { - div.details-list-item:nth-child(2n) { + div.details-list-item:nth-child(2n-1) { background-color: rgba($lt-bg-color-lvl5-light, .4); } @@ -57,7 +57,7 @@ div.light.details-list { div.dark.details-list { - div.details-list-item:nth-child(2n) { + div.details-list-item:nth-child(2n-1) { background-color: rgba($lt-bg-color-lvl5-dark, .8); } diff --git a/source/Model/Model.ts b/source/Model/Model.ts index 0a4ebb0..95fd3c8 100644 --- a/source/Model/Model.ts +++ b/source/Model/Model.ts @@ -171,9 +171,6 @@ class Model extends Emitter { */ public update(t: number) { - // 清除全部渲染状态 - this.renderer.clean(); - // 第一轮更新 for (let i = 0; i < this.objectPool.length; i++) { let object = this.objectPool[i]; @@ -198,6 +195,16 @@ class Model extends Emitter { } } + this.draw(); + + this.emit("loop", t); + } + + public draw() { + + // 清除全部渲染状态 + this.renderer.clean(); + // 渲染 for (let i = 0; i < this.objectPool.length; i++) { let object = this.objectPool[i]; @@ -214,8 +221,6 @@ class Model extends Emitter { } as any); } } - - this.emit("loop", t); } } diff --git a/source/Panel/ObjectList/ObjectCommand.tsx b/source/Panel/ObjectList/ObjectCommand.tsx new file mode 100644 index 0000000..5af857b --- /dev/null +++ b/source/Panel/ObjectList/ObjectCommand.tsx @@ -0,0 +1,78 @@ +import { BackgroundLevel, FontLevel, Theme } from "@Component/Theme/Theme"; +import { useStatus, IMixinStatusProps } from "../../Context/Status"; +import { Icon } from "@fluentui/react"; +import { Component, ReactNode } from "react"; +import { ObjectID } from "@Model/Renderer"; +import "./ObjectList.scss"; + +@useStatus +class ObjectCommand extends Component { + public render(): ReactNode { + return +
{ + if (this.props.status) { + let allObjSet = new Set(); + this.props.status.model.objectPool.forEach((obj) => { + allObjSet.add(obj.id.toString()); + }) + this.props.status.setFocusObject(allObjSet); + } + }} + > + +
+
{ + if (this.props.status) { + this.props.status.setFocusObject(new Set()); + } + }} + > + +
+
{ + this.props.status ? this.props.status.newGroup() : undefined; + this.props.status ? this.props.status.model.draw() : undefined; + }} + > + +
+
{ + this.props.status ? this.props.status.newRange() : undefined; + this.props.status ? this.props.status.model.draw() : undefined; + }} + > + +
+
{ + if (this.props.status) { + let deleteId: ObjectID[] = []; + this.props.status.focusObject.forEach((obj) => { + deleteId.push(obj); + }) + this.props.status.model.deleteObject(deleteId); + this.props.status.setFocusObject(new Set()); + this.props.status.model.draw(); + } + }} + > + +
+
+ } +} + +export { ObjectCommand }; \ No newline at end of file diff --git a/source/Panel/ObjectList/ObjectList.scss b/source/Panel/ObjectList/ObjectList.scss index 1f4cb47..c82464d 100644 --- a/source/Panel/ObjectList/ObjectList.scss +++ b/source/Panel/ObjectList/ObjectList.scss @@ -1,3 +1,5 @@ +@import "../../Component/Theme/Theme.scss"; + div.object-list-color-value { height: calc( 100% - 6px); margin: 3px 0; @@ -8,4 +10,35 @@ div.object-list-color-value { div.object-list { min-height: 100%; +} + +div.object-list-command-bar { + width: 100%; + height: 30px; + flex-shrink: 0; + display: flex; + + div.command-item{ + width: 30px; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + user-select: none; + cursor: pointer; + } +} + +div.dark.object-list-command-bar { + + div.command-item:hover { + background-color: $lt-bg-color-lvl3-dark; + } +} + +div.light.object-list-command-bar { + + div.command-item:hover { + background-color: $lt-bg-color-lvl3-light; + } } \ No newline at end of file diff --git a/source/Panel/ObjectList/ObjectList.tsx b/source/Panel/ObjectList/ObjectList.tsx index 7104cb9..cff972f 100644 --- a/source/Panel/ObjectList/ObjectList.tsx +++ b/source/Panel/ObjectList/ObjectList.tsx @@ -1,12 +1,14 @@ import { Component, ReactNode } from "react"; import { DetailsList } from "@Component/DetailsList/DetailsList"; import { useStatus, IMixinStatusProps } from "@Context/Status"; +import { useSetting, IMixinSettingProps } from "@Context/Setting"; import { Localization } from "@Component/Localization/Localization"; import { ObjectID } from "@Model/Renderer"; import "./ObjectList.scss"; +@useSetting @useStatus -class ObjectList extends Component { +class ObjectList extends Component { private handelChange = () => { this.forceUpdate(); @@ -52,11 +54,17 @@ 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)); } }} checkBox={(item) => { + if (this.props.setting) { + this.props.setting.layout.focus("ObjectList"); + } if (this.props.status) { if ( this.props.status.focusObject.has(item.key.toString()) || diff --git a/source/Panel/Panel.tsx b/source/Panel/Panel.tsx index 7bda3a7..47a684e 100644 --- a/source/Panel/Panel.tsx +++ b/source/Panel/Panel.tsx @@ -3,11 +3,13 @@ import { Theme } from "@Component/Theme/Theme"; import { Localization } from "@Component/Localization/Localization"; import { RenderView } from "./RenderView/RenderView"; import { ObjectList } from "./ObjectList/ObjectList"; +import { ObjectCommand } from "./ObjectList/ObjectCommand"; interface IPanelInfo { nameKey: string; introKay: string; class: (new (...p: any) => Component) | FunctionComponent; + header?: (new (...p: any) => Component) | FunctionComponent; hidePadding?: boolean; hideScrollBar?: boolean; isDeepDark?: boolean; @@ -26,7 +28,7 @@ PanelInfoMap.set("RenderView", { }); PanelInfoMap.set("ObjectList", { nameKey: "Panel.Title.Object.List.View", introKay: "Panel.Info.Object.List.View", - class: ObjectList, hidePadding: true + class: ObjectList, header: ObjectCommand, hidePadding: true }) function getPanelById(panelId: PanelId): ReactNode {