Update use status api with mount event

This commit is contained in:
MrKBear 2022-03-07 10:43:23 +08:00
parent 779076012f
commit 9bc8ddf061
6 changed files with 93 additions and 57 deletions

View File

@ -2,7 +2,7 @@ import { BackgroundLevel, Theme } from "@Component/Theme/Theme";
import { DirectionalHint, IconButton } from "@fluentui/react"; import { DirectionalHint, IconButton } from "@fluentui/react";
import { LocalizationTooltipHost } from "../Localization/LocalizationTooltipHost"; import { LocalizationTooltipHost } from "../Localization/LocalizationTooltipHost";
import { useSetting, IMixinSettingProps } from "@Context/Setting"; import { useSetting, IMixinSettingProps } from "@Context/Setting";
import { useStatus, IMixinStatusProps } from "@Context/Status"; import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status";
import { AllI18nKeys } from "../Localization/Localization"; import { AllI18nKeys } from "../Localization/Localization";
import { Component, ReactNode } from "react"; import { Component, ReactNode } from "react";
import { MouseMod } from "@GLRender/ClassicRenderer"; import { MouseMod } from "@GLRender/ClassicRenderer";
@ -12,26 +12,10 @@ interface ICommandBarProps {
width: number; width: number;
} }
@useStatus
@useSetting @useSetting
@useStatusWithEvent("mouseModChange")
class CommandBar extends Component<ICommandBarProps & IMixinSettingProps & IMixinStatusProps> { class CommandBar extends Component<ICommandBarProps & IMixinSettingProps & IMixinStatusProps> {
private handelChange = () => {
this.forceUpdate();
}
componentDidMount() {
if (this.props.status) {
this.props.status.on("mouseModChange", this.handelChange)
}
}
componentWillUnmount() {
if (this.props.status) {
this.props.status.off("mouseModChange", this.handelChange)
}
}
render(): ReactNode { render(): ReactNode {
const mouseMod = this.props.status?.mouseMod ?? MouseMod.Drag; const mouseMod = this.props.status?.mouseMod ?? MouseMod.Drag;
@ -64,7 +48,6 @@ class CommandBar extends Component<ICommandBarProps & IMixinSettingProps & IMixi
i18NKey: "Command.Bar.Add.Group.Info", i18NKey: "Command.Bar.Add.Group.Info",
click: () => { click: () => {
this.props.status ? this.props.status.newGroup() : undefined; this.props.status ? this.props.status.newGroup() : undefined;
this.props.status ? this.props.status.model.draw() : undefined;
} }
})} })}
{this.getRenderButton({ {this.getRenderButton({
@ -72,7 +55,6 @@ class CommandBar extends Component<ICommandBarProps & IMixinSettingProps & IMixi
i18NKey: "Command.Bar.Add.Range.Info", i18NKey: "Command.Bar.Add.Range.Info",
click: () => { click: () => {
this.props.status ? this.props.status.newRange() : undefined; this.props.status ? this.props.status.newRange() : undefined;
this.props.status ? this.props.status.model.draw() : undefined;
} }
})} })}
{this.getRenderButton({ iconName: "StepSharedAdd", i18NKey: "Command.Bar.Add.Behavior.Info" })} {this.getRenderButton({ iconName: "StepSharedAdd", i18NKey: "Command.Bar.Add.Behavior.Info" })}

View File

@ -62,8 +62,8 @@ class HeaderBar extends Component<
} }
if (status) { if (status) {
status.archive.on("save", this.changeListener); status.archive.on("save", this.changeListener);
status.model.on("loop", this.physicsFpsCalc); status.on("physicsLoop", this.physicsFpsCalc);
status.renderer.on("loop", this.renderFpsCalc); status.on("renderLoop", this.renderFpsCalc);
} }
} }
@ -74,8 +74,8 @@ class HeaderBar extends Component<
} }
if (status) { if (status) {
status.archive.off("save", this.changeListener); status.archive.off("save", this.changeListener);
status.model.off("loop", this.physicsFpsCalc); status.off("physicsLoop", this.physicsFpsCalc);
status.renderer.off("loop", this.renderFpsCalc); status.off("renderLoop", this.renderFpsCalc);
} }
} }

View File

@ -1,8 +1,7 @@
import { createContext, Component, FunctionComponent } from "react"; import { createContext, Component, FunctionComponent, useState, useEffect, ReactNode } from "react";
import { Emitter } from "@Model/Emitter"; import { Emitter } from "@Model/Emitter";
import { Model, ObjectID } from "@Model/Model"; import { Model, ObjectID } from "@Model/Model";
import { Archive } from "@Model/Archive"; import { Archive } from "@Model/Archive";
import { CtrlObject } from "@Model/CtrlObject";
import { AbstractRenderer } from "@Model/Renderer"; import { AbstractRenderer } from "@Model/Renderer";
import { ClassicRenderer, MouseMod } from "@GLRender/ClassicRenderer"; import { ClassicRenderer, MouseMod } from "@GLRender/ClassicRenderer";
import { Setting } from "./Setting"; import { Setting } from "./Setting";
@ -16,10 +15,16 @@ function randomColor() {
] ]
} }
class Status extends Emitter<{ interface IStatusEvent {
mouseModChange: MouseMod, renderLoop: number;
focusObjectChange: Set<ObjectID> physicsLoop: number;
}> { mouseModChange: void;
focusObjectChange: void;
objectChange: void;
labelChange: void;
}
class Status extends Emitter<IStatusEvent> {
public setting: Setting = undefined as any; public setting: Setting = undefined as any;
@ -48,12 +53,34 @@ class Status extends Emitter<{
*/ */
public focusObject: Set<ObjectID> = new Set(); public focusObject: Set<ObjectID> = new Set();
public constructor() {
super();
// 循环事件
this.model.on("loop", (t) => { this.emit("physicsLoop", t) });
// 对象变化事件
this.model.on("objectChange", () => this.emit("objectChange"));
this.model.on("labelChange", () => this.emit("labelChange"));
// 对象变换时执行渲染,更新渲染器数据
this.on("objectChange", () => {
this.model.draw();
})
}
public bindRenderer(renderer: AbstractRenderer) {
this.renderer = renderer;
this.renderer.on("loop", (t) => { this.emit("renderLoop", t) });
this.model.bindRenderer(this.renderer);
}
/** /**
* *
*/ */
public setFocusObject(focusObject: Set<ObjectID>) { public setFocusObject(focusObject: Set<ObjectID>) {
this.focusObject = focusObject; this.focusObject = focusObject;
this.emit("focusObjectChange", this.focusObject); this.emit("focusObjectChange");
} }
/** /**
@ -87,7 +114,7 @@ class Status extends Emitter<{
this.renderer.mouseMod = mod; this.renderer.mouseMod = mod;
this.renderer.setMouseIcon(); this.renderer.setMouseIcon();
} }
this.emit("mouseModChange", mod); this.emit("mouseModChange");
} }
} }
@ -116,7 +143,55 @@ function useStatus<R extends RenderComponent>(components: R): R {
}) as any; }) as any;
} }
function useStatusWithEvent(...events: Array<keyof IStatusEvent>) {
return <R extends RenderComponent>(components: R): R => {
const C = components as any;
return class extends Component<R> {
private status: Status | undefined;
private isEventMount: boolean = false;
private handelChange = () => {
this.forceUpdate();
}
private mountEvent() {
if (this.status && !this.isEventMount) {
this.isEventMount = true;
console.log("event mount");
for (let i = 0; i < events.length; i++) {
this.status.on(events[i], this.handelChange);
}
}
}
private unmountEvent() {
if (this.status) {
for (let i = 0; i < events.length; i++) {
this.status.off(events[i], this.handelChange);
}
}
}
public render(): ReactNode {
return <StatusConsumer>
{(status: Status) => {
this.status = status;
this.mountEvent();
return <C {...this.props} status={status}></C>;
}}
</StatusConsumer>
}
public componentWillUnmount() {
this.unmountEvent();
}
} as any;
}
}
export { export {
Status, StatusContext, useStatus, Status, StatusContext, useStatus, useStatusWithEvent,
IMixinStatusProps, StatusProvider, StatusConsumer IMixinStatusProps, StatusProvider, StatusConsumer
}; };

View File

@ -35,7 +35,7 @@ class SimulatorWeb extends Component {
// TODO: 这里要读取存档 // TODO: 这里要读取存档
this.status = new Status(); this.status = new Status();
this.status.renderer = new ClassicRenderer({ className: "canvas" }).onLoad(); this.status.renderer = new ClassicRenderer({ className: "canvas" }).onLoad();
this.status.model.bindRenderer(this.status.renderer); this.status.bindRenderer(this.status.renderer);
this.status.setting = this.setting; this.status.setting = this.setting;
// 测试代码 // 测试代码

View File

@ -41,7 +41,6 @@ class ObjectCommand extends Component<IMixinStatusProps> {
className="command-item" className="command-item"
onClick={() => { onClick={() => {
this.props.status ? this.props.status.newGroup() : undefined; this.props.status ? this.props.status.newGroup() : undefined;
this.props.status ? this.props.status.model.draw() : undefined;
}} }}
> >
<Icon iconName="WebAppBuilderFragmentCreate"></Icon> <Icon iconName="WebAppBuilderFragmentCreate"></Icon>
@ -50,7 +49,6 @@ class ObjectCommand extends Component<IMixinStatusProps> {
className="command-item" className="command-item"
onClick={() => { onClick={() => {
this.props.status ? this.props.status.newRange() : undefined; this.props.status ? this.props.status.newRange() : undefined;
this.props.status ? this.props.status.model.draw() : undefined;
}} }}
> >
<Icon iconName="CubeShape"></Icon> <Icon iconName="CubeShape"></Icon>
@ -65,7 +63,6 @@ class ObjectCommand extends Component<IMixinStatusProps> {
}) })
this.props.status.model.deleteObject(deleteId); this.props.status.model.deleteObject(deleteId);
this.props.status.setFocusObject(new Set<ObjectID>()); this.props.status.setFocusObject(new Set<ObjectID>());
this.props.status.model.draw();
} }
}} }}
> >

View File

@ -1,33 +1,15 @@
import { Component, ReactNode } from "react"; import { Component, ReactNode } from "react";
import { DetailsList } from "@Component/DetailsList/DetailsList"; import { DetailsList } from "@Component/DetailsList/DetailsList";
import { useStatus, IMixinStatusProps } from "@Context/Status"; import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status";
import { useSetting, IMixinSettingProps } from "@Context/Setting"; import { useSetting, IMixinSettingProps } from "@Context/Setting";
import { Localization } from "@Component/Localization/Localization"; import { Localization } from "@Component/Localization/Localization";
import { ObjectID } from "@Model/Renderer"; import { ObjectID } from "@Model/Renderer";
import "./ObjectList.scss"; import "./ObjectList.scss";
@useSetting @useSetting
@useStatus @useStatusWithEvent("objectChange", "focusObjectChange")
class ObjectList extends Component<IMixinStatusProps & IMixinSettingProps> { class ObjectList extends Component<IMixinStatusProps & IMixinSettingProps> {
private handelChange = () => {
this.forceUpdate();
}
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);
}
}
private renderList() { private renderList() {
const objList = this.props.status?.model.objectPool ?? []; const objList = this.props.status?.model.objectPool ?? [];