Add object list command bar & checkbox handel func #14
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -90,10 +90,25 @@ class Container extends Component<IContainerProps> {
|
||||
}</div> : null
|
||||
}
|
||||
<div
|
||||
className={[
|
||||
"app-panel-root",
|
||||
hasActivePanel ? "active" : ""
|
||||
].filter(x => !!x).join(" ")}
|
||||
onClick={() => this.props.onFocusTab ? this.props.onFocusTab(showPanelId) : undefined}
|
||||
>
|
||||
{/* 渲染 Command Bar */}
|
||||
{(() => {
|
||||
let info = getPanelInfoById(showPanelId as any);
|
||||
if (info && info.header) {
|
||||
const Header = info.header;
|
||||
return <Header></Header>
|
||||
}
|
||||
})()}
|
||||
|
||||
{/* 渲染 Panel 内容 */}
|
||||
<div
|
||||
className={[
|
||||
"app-panel",
|
||||
hasActivePanel ? "active" : "",
|
||||
showPanelInfo?.hidePadding ? "" : "has-padding",
|
||||
showPanelInfo?.hideScrollBar ? "hide-scrollbar" : ""
|
||||
].filter(x => !!x).join(" ")}
|
||||
@ -101,6 +116,7 @@ class Container extends Component<IContainerProps> {
|
||||
>
|
||||
{getPanelById(showPanelId as any)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
||||
|
@ -19,31 +19,58 @@ 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
div.details-list-item:nth-child(2n-1) {
|
||||
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);
|
||||
// }
|
||||
}
|
@ -16,9 +16,13 @@ interface IColumns<D extends IItems, K extends keyof D> {
|
||||
|
||||
interface IDetailsListProps {
|
||||
items: IItems[];
|
||||
className?: string;
|
||||
columns: IColumns<this["items"][number], keyof this["items"][number]>[];
|
||||
hideCheckBox?: boolean;
|
||||
checkboxClassName?: string;
|
||||
click?: () => void;
|
||||
clickLine?: (item: IItems) => any;
|
||||
checkBox?: (data: IItems) => any;
|
||||
}
|
||||
|
||||
class DetailsList extends Component<IDetailsListProps> {
|
||||
@ -41,13 +45,27 @@ class DetailsList extends Component<IDetailsListProps> {
|
||||
|
||||
public render(): ReactNode {
|
||||
return <Theme
|
||||
className="details-list"
|
||||
className={"details-list" + (this.props.className ? ` ${this.props.className}` : "")}
|
||||
onClick={this.props.click}
|
||||
backgroundLevel={BackgroundLevel.Level4}
|
||||
fontLevel={FontLevel.normal}
|
||||
>{
|
||||
this.props.items.map((item) => {
|
||||
const { checkboxClassName } = this.props;
|
||||
return <div className="details-list-item" key={item.key}>
|
||||
const classList: string[] = ["details-list-item"];
|
||||
if (item.select) {
|
||||
classList.push("active");
|
||||
}
|
||||
return <div
|
||||
className={classList.join(" ")}
|
||||
key={item.key}
|
||||
onClick={(e) => {
|
||||
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<IDetailsListProps> {
|
||||
this.props.hideCheckBox ? null :
|
||||
<div
|
||||
className={"details-list-checkbox" + (checkboxClassName ? ` ${checkboxClassName}` : "")}
|
||||
onClick={(e) => {
|
||||
if (this.props.checkBox) {
|
||||
e.stopPropagation();
|
||||
this.props.checkBox(item);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Icon iconName="CheckMark"></Icon>
|
||||
</div>
|
||||
@ -76,4 +100,4 @@ class DetailsList extends Component<IDetailsListProps> {
|
||||
}
|
||||
}
|
||||
|
||||
export { DetailsList };
|
||||
export { DetailsList, IItems };
|
@ -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<ObjectID>
|
||||
}> {
|
||||
|
||||
public setting: Setting = undefined as any;
|
||||
@ -41,6 +43,19 @@ class Status extends Emitter<{
|
||||
*/
|
||||
public model: Model = new Model();
|
||||
|
||||
/**
|
||||
* 焦点对象
|
||||
*/
|
||||
public focusObject: Set<ObjectID> = new Set();
|
||||
|
||||
/**
|
||||
* 更新焦点对象
|
||||
*/
|
||||
public setFocusObject(focusObject: Set<ObjectID>) {
|
||||
this.focusObject = focusObject;
|
||||
this.emit("focusObjectChange", this.focusObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* 鼠标工具状态
|
||||
*/
|
||||
|
@ -37,6 +37,14 @@ class Model extends Emitter<ModelEvent> {
|
||||
*/
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 标签列表
|
||||
*/
|
||||
@ -163,9 +171,6 @@ class Model extends Emitter<ModelEvent> {
|
||||
*/
|
||||
public update(t: number) {
|
||||
|
||||
// 清除全部渲染状态
|
||||
this.renderer.clean();
|
||||
|
||||
// 第一轮更新
|
||||
for (let i = 0; i < this.objectPool.length; i++) {
|
||||
let object = this.objectPool[i];
|
||||
@ -190,6 +195,16 @@ class Model extends Emitter<ModelEvent> {
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
@ -206,8 +221,6 @@ class Model extends Emitter<ModelEvent> {
|
||||
} as any);
|
||||
}
|
||||
}
|
||||
|
||||
this.emit("loop", t);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
78
source/Panel/ObjectList/ObjectCommand.tsx
Normal file
78
source/Panel/ObjectList/ObjectCommand.tsx
Normal file
@ -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<IMixinStatusProps> {
|
||||
public render(): ReactNode {
|
||||
return <Theme
|
||||
className="object-list-command-bar"
|
||||
backgroundLevel={BackgroundLevel.Level4}
|
||||
fontLevel={FontLevel.normal}
|
||||
>
|
||||
<div
|
||||
className="command-item"
|
||||
onClick={() => {
|
||||
if (this.props.status) {
|
||||
let allObjSet = new Set<ObjectID>();
|
||||
this.props.status.model.objectPool.forEach((obj) => {
|
||||
allObjSet.add(obj.id.toString());
|
||||
})
|
||||
this.props.status.setFocusObject(allObjSet);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Icon iconName="CheckMark"></Icon>
|
||||
</div>
|
||||
<div
|
||||
className="command-item"
|
||||
onClick={() => {
|
||||
if (this.props.status) {
|
||||
this.props.status.setFocusObject(new Set<ObjectID>());
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Icon iconName="CalculatorMultiply"></Icon>
|
||||
</div>
|
||||
<div
|
||||
className="command-item"
|
||||
onClick={() => {
|
||||
this.props.status ? this.props.status.newGroup() : undefined;
|
||||
this.props.status ? this.props.status.model.draw() : undefined;
|
||||
}}
|
||||
>
|
||||
<Icon iconName="WebAppBuilderFragmentCreate"></Icon>
|
||||
</div>
|
||||
<div
|
||||
className="command-item"
|
||||
onClick={() => {
|
||||
this.props.status ? this.props.status.newRange() : undefined;
|
||||
this.props.status ? this.props.status.model.draw() : undefined;
|
||||
}}
|
||||
>
|
||||
<Icon iconName="CubeShape"></Icon>
|
||||
</div>
|
||||
<div
|
||||
className="command-item"
|
||||
onClick={() => {
|
||||
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<ObjectID>());
|
||||
this.props.status.model.draw();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Icon iconName="Delete"></Icon>
|
||||
</div>
|
||||
</Theme>
|
||||
}
|
||||
}
|
||||
|
||||
export { ObjectCommand };
|
@ -1,3 +1,5 @@
|
||||
@import "../../Component/Theme/Theme.scss";
|
||||
|
||||
div.object-list-color-value {
|
||||
height: calc( 100% - 6px);
|
||||
margin: 3px 0;
|
||||
@ -5,3 +7,38 @@ div.object-list-color-value {
|
||||
border-radius: 1000px;
|
||||
width: 3px;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@ -1,11 +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<IMixinStatusProps> {
|
||||
class ObjectList extends Component<IMixinStatusProps & IMixinSettingProps> {
|
||||
|
||||
private handelChange = () => {
|
||||
this.forceUpdate();
|
||||
@ -14,12 +17,14 @@ class ObjectList extends Component<IMixinStatusProps> {
|
||||
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 +39,50 @@ class ObjectList extends Component<IMixinStatusProps> {
|
||||
}
|
||||
|
||||
return <DetailsList
|
||||
className="object-list"
|
||||
items={objList.concat([]).map((object => {
|
||||
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.setting) {
|
||||
this.props.setting.layout.focus("ObjectList");
|
||||
}
|
||||
if (this.props.status) {
|
||||
this.props.status.setFocusObject(new Set<ObjectID>().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()) ||
|
||||
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<ObjectID>());
|
||||
}
|
||||
}}
|
||||
columns={[
|
||||
{
|
||||
key: "color",
|
||||
|
@ -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 {
|
||||
|
@ -28,7 +28,7 @@ class RenderView extends Component<IMixinStatusProps & IMixinSettingProps> {
|
||||
|
||||
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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user