Add desktop layout
This commit is contained in:
parent
fca467a427
commit
eccd7fdf7c
@ -1,11 +1,16 @@
|
||||
div.header-bar {
|
||||
padding: 0 3px;
|
||||
@import "../Theme/Theme.scss";
|
||||
|
||||
div.header-bar {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
user-select: none;
|
||||
|
||||
div.title {
|
||||
padding-left: 3px;
|
||||
}
|
||||
|
||||
div.title > i, div.fps-view > i {
|
||||
font-size: 25px;
|
||||
vertical-align: middle;
|
||||
@ -24,4 +29,43 @@ div.header-bar {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
div.header-windows-action {
|
||||
height: 100%;
|
||||
width: 135px;
|
||||
min-width: 135px;
|
||||
display: flex;
|
||||
|
||||
div.action-button {
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: .5em;
|
||||
}
|
||||
|
||||
div.action-button:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
div.action-button.close-button:hover {
|
||||
color: #FFFFFF !important;
|
||||
background-color: $lt-red !important;
|
||||
}
|
||||
}
|
||||
|
||||
div.header-windows-action.light {
|
||||
|
||||
div.action-button:hover {
|
||||
background-color: rgba($color: #000000, $alpha: .1);
|
||||
}
|
||||
}
|
||||
|
||||
div.header-windows-action.dark {
|
||||
|
||||
div.action-button:hover {
|
||||
background-color: rgba($color: #FFFFFF, $alpha: .1);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import { Component, ReactNode } from "react";
|
||||
import { Icon } from '@fluentui/react/lib/Icon';
|
||||
import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status";
|
||||
import { useSetting, IMixinSettingProps } from "@Context/Setting";
|
||||
import { useStatusWithEvent, useStatus, IMixinStatusProps } from "@Context/Status";
|
||||
import { useSettingWithEvent, IMixinSettingProps, Platform } from "@Context/Setting";
|
||||
import { Theme, BackgroundLevel, FontLevel } from "@Component/Theme/Theme";
|
||||
import { LocalizationTooltipHost } from "@Component/Localization/LocalizationTooltipHost";
|
||||
import { I18N } from "@Component/Localization/Localization";
|
||||
@ -11,38 +11,48 @@ interface IHeaderBarProps {
|
||||
height: number;
|
||||
}
|
||||
|
||||
interface HeaderBarState {
|
||||
interface IHeaderFpsViewState {
|
||||
renderFps: number;
|
||||
physicsFps: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 头部信息栏
|
||||
*/
|
||||
@useSetting
|
||||
@useStatusWithEvent("fileChange")
|
||||
class HeaderBar extends Component<
|
||||
IHeaderBarProps & IMixinStatusProps & IMixinSettingProps,
|
||||
HeaderBarState
|
||||
> {
|
||||
@useStatus
|
||||
class HeaderFpsView extends Component<IMixinStatusProps & IMixinSettingProps, IHeaderFpsViewState> {
|
||||
|
||||
public state = {
|
||||
renderFps: 0,
|
||||
physicsFps: 0,
|
||||
}
|
||||
|
||||
private changeListener = () => {
|
||||
this.forceUpdate();
|
||||
private updateTime: number = 0;
|
||||
|
||||
private renderFpsCalc: (t: number) => void = () => {};
|
||||
private physicsFpsCalc: (t: number) => void = () => {};
|
||||
|
||||
public componentDidMount() {
|
||||
const { status } = this.props;
|
||||
this.renderFpsCalc = this.createFpsCalc("renderFps");
|
||||
this.physicsFpsCalc = this.createFpsCalc("physicsFps");
|
||||
if (status) {
|
||||
status.on("physicsLoop", this.physicsFpsCalc);
|
||||
status.on("renderLoop", this.renderFpsCalc);
|
||||
}
|
||||
}
|
||||
|
||||
private updateTime: number = 0;
|
||||
public componentWillUnmount() {
|
||||
const { status } = this.props;
|
||||
if (status) {
|
||||
status.off("physicsLoop", this.physicsFpsCalc);
|
||||
status.off("renderLoop", this.renderFpsCalc);
|
||||
}
|
||||
}
|
||||
|
||||
private createFpsCalc(type: "renderFps" | "physicsFps") {
|
||||
return (t: number) => {
|
||||
if (t === 0) {
|
||||
return;
|
||||
}
|
||||
let newState: HeaderBarState = {} as any;
|
||||
let newState: IHeaderFpsViewState = {} as any;
|
||||
newState[type] = 1 / t;
|
||||
if (this.updateTime > 20) {
|
||||
this.updateTime = 0;
|
||||
@ -52,49 +62,59 @@ class HeaderBar extends Component<
|
||||
}
|
||||
}
|
||||
|
||||
private renderFpsCalc: (t: number) => void = () => {};
|
||||
private physicsFpsCalc: (t: number) => void = () => {};
|
||||
|
||||
public componentDidMount() {
|
||||
const { setting, status } = this.props;
|
||||
this.renderFpsCalc = this.createFpsCalc("renderFps");
|
||||
this.physicsFpsCalc = this.createFpsCalc("physicsFps");
|
||||
if (setting) {
|
||||
setting.on("language", this.changeListener);
|
||||
}
|
||||
if (status) {
|
||||
status.on("physicsLoop", this.physicsFpsCalc);
|
||||
status.on("renderLoop", this.renderFpsCalc);
|
||||
}
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
const { setting, status } = this.props;
|
||||
if (setting) {
|
||||
setting.off("language", this.changeListener);
|
||||
}
|
||||
if (status) {
|
||||
status.off("physicsLoop", this.physicsFpsCalc);
|
||||
status.off("renderLoop", this.renderFpsCalc);
|
||||
}
|
||||
}
|
||||
|
||||
public render(): ReactNode {
|
||||
const { status } = this.props;
|
||||
let fileName: string = "";
|
||||
let isNewFile: boolean = true;
|
||||
let isSaved: boolean = false;
|
||||
if (status) {
|
||||
isNewFile = status.archive.isNewFile;
|
||||
fileName = status.archive.fileName ?? "";
|
||||
isSaved = status.archive.isSaved;
|
||||
}
|
||||
public render() {
|
||||
|
||||
const fpsInfo = {
|
||||
renderFps: Math.floor(this.state.renderFps).toString(),
|
||||
physicsFps: Math.floor(this.state.physicsFps).toString()
|
||||
};
|
||||
|
||||
return <LocalizationTooltipHost i18nKey="Header.Bar.Fps.Info" options={fpsInfo}>
|
||||
<div className="fps-view">
|
||||
<Icon iconName="SpeedHigh"></Icon>
|
||||
<span>{I18N(this.props, "Header.Bar.Fps", fpsInfo)}</span>
|
||||
</div>
|
||||
</LocalizationTooltipHost>
|
||||
}
|
||||
}
|
||||
|
||||
class HeaderWindowsAction extends Component {
|
||||
|
||||
public render() {
|
||||
return <Theme className="header-windows-action">
|
||||
<div className="action-button">
|
||||
<Icon iconName="ChromeMinimize"/>
|
||||
</div>
|
||||
<div className="action-button">
|
||||
<Icon iconName="ChromeRestore"/>
|
||||
</div>
|
||||
<div className="action-button close-button">
|
||||
<Icon iconName="ChromeClose"/>
|
||||
</div>
|
||||
</Theme>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 头部信息栏
|
||||
*/
|
||||
@useSettingWithEvent("language")
|
||||
@useStatusWithEvent("fileChange")
|
||||
class HeaderBar extends Component<IHeaderBarProps & IMixinStatusProps & IMixinSettingProps> {
|
||||
|
||||
public render(): ReactNode {
|
||||
const { status, setting } = this.props;
|
||||
|
||||
let fileName: string = "";
|
||||
let isNewFile: boolean = true;
|
||||
let isSaved: boolean = false;
|
||||
|
||||
if (status) {
|
||||
isNewFile = status.archive.isNewFile;
|
||||
fileName = status.archive.fileName ?? "";
|
||||
isSaved = status.archive.isSaved;
|
||||
}
|
||||
|
||||
return <Theme
|
||||
className="header-bar"
|
||||
backgroundLevel={BackgroundLevel.Level1}
|
||||
@ -125,15 +145,15 @@ class HeaderBar extends Component<
|
||||
isSaved ? "" : "*"
|
||||
}</div>
|
||||
</LocalizationTooltipHost>
|
||||
<LocalizationTooltipHost i18nKey="Header.Bar.Fps.Info" options={fpsInfo}>
|
||||
<div className="fps-view">
|
||||
<Icon iconName="SpeedHigh"></Icon>
|
||||
<span>{I18N(this.props, "Header.Bar.Fps", fpsInfo)}</span>
|
||||
</div>
|
||||
</LocalizationTooltipHost>
|
||||
|
||||
{
|
||||
setting?.platform === Platform.desktop ?
|
||||
<HeaderWindowsAction/> :
|
||||
<HeaderFpsView setting={setting}/>
|
||||
}
|
||||
|
||||
</Theme>
|
||||
}
|
||||
}
|
||||
|
||||
export default HeaderBar;
|
||||
export { HeaderBar };
|
@ -11,6 +11,11 @@ enum Themes {
|
||||
dark = 2
|
||||
}
|
||||
|
||||
enum Platform {
|
||||
web = 1,
|
||||
desktop = 2
|
||||
}
|
||||
|
||||
type Language = "ZH_CN" | "EN_US";
|
||||
|
||||
interface ISettingEvents extends Setting {
|
||||
@ -19,6 +24,11 @@ interface ISettingEvents extends Setting {
|
||||
|
||||
class Setting extends Emitter<ISettingEvents> {
|
||||
|
||||
/**
|
||||
* 程序平台
|
||||
*/
|
||||
public platform: Platform = Platform.web;
|
||||
|
||||
/**
|
||||
* 主题
|
||||
*/
|
||||
@ -63,5 +73,5 @@ const useSettingWithEvent = superConnectWithEvent<Setting, ISettingEvents>(Setti
|
||||
|
||||
export {
|
||||
Themes, Setting, SettingContext, useSetting, Language, useSettingWithEvent,
|
||||
IMixinSettingProps, SettingProvider, SettingConsumer
|
||||
IMixinSettingProps, SettingProvider, SettingConsumer, Platform
|
||||
};
|
@ -9,6 +9,8 @@ const EN_US = {
|
||||
"Header.Bar.File.Save.Status.Unsaved": "UnSaved",
|
||||
"Header.Bar.Fps": "FPS: {renderFps} | {physicsFps}",
|
||||
"Header.Bar.Fps.Info": "The rendering frame rate ({renderFps} fps) is on the left, and the simulation frame rate ({physicsFps} fps) is on the right.",
|
||||
"Header.Bar.Fps.Render.Info": "Render fps {fps}",
|
||||
"Header.Bar.Fps.Simulate.Info": "Simulate fps {fps}",
|
||||
"Command.Bar.Save.Info": "Save",
|
||||
"Command.Bar.Play.Info": "Start simulation",
|
||||
"Command.Bar.Drag.Info": "Drag and drop to move the camera",
|
||||
|
@ -9,6 +9,8 @@ const ZH_CN = {
|
||||
"Header.Bar.File.Save.Status.Unsaved": "未保存",
|
||||
"Header.Bar.Fps": "帧率: {renderFps} | {physicsFps}",
|
||||
"Header.Bar.Fps.Info": "左侧为渲染帧率 ({renderFps} fps), 右侧为模拟帧率 ({physicsFps} fps)。",
|
||||
"Header.Bar.Fps.Render.Info": "渲染帧率 {fps}",
|
||||
"Header.Bar.Fps.Simulate.Info": "模拟帧率 {fps}",
|
||||
"Command.Bar.Save.Info": "保存",
|
||||
"Command.Bar.Play.Info": "开始仿真",
|
||||
"Command.Bar.Drag.Info": "拖拽进行视角移动",
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Component, ReactNode } from "react";
|
||||
import { SettingProvider, Setting } from "@Context/Setting";
|
||||
import { SettingProvider, Setting, Platform } from "@Context/Setting";
|
||||
import { Theme, BackgroundLevel, FontLevel } from "@Component/Theme/Theme";
|
||||
import { StatusProvider, Status } from "@Context/Status";
|
||||
import { ClassicRenderer } from "@GLRender/ClassicRenderer";
|
||||
@ -33,7 +33,7 @@ class SimulatorWeb extends Component {
|
||||
|
||||
// TODO: 这里要读取设置
|
||||
this.setting = new Setting();
|
||||
(window as any).setting = (this.setting as any);
|
||||
this.setting.platform = Platform.web;
|
||||
|
||||
// TODO: 这里要读取存档
|
||||
const classicRender = new ClassicRenderer().onLoad();
|
||||
|
@ -6,4 +6,17 @@ div.render-view {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
div.render-view-fps {
|
||||
height: 0;
|
||||
width: 100%;
|
||||
|
||||
div.fps-view {
|
||||
position: relative;
|
||||
opacity: .5;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
user-select: none;
|
||||
}
|
||||
}
|
@ -1,9 +1,85 @@
|
||||
import { Component, ReactNode, createRef } from "react";
|
||||
import { useStatus, IMixinStatusProps } from "@Context/Status";
|
||||
import { useSetting, IMixinSettingProps, Themes } from "@Context/Setting";
|
||||
import { useSetting, IMixinSettingProps, Themes, Platform } from "@Context/Setting";
|
||||
import { ClassicRenderer } from "@GLRender/ClassicRenderer";
|
||||
import { FontLevel, Theme } from "@Component/Theme/Theme";
|
||||
import { Localization } from "@Component/Localization/Localization";
|
||||
import "./RenderView.scss";
|
||||
|
||||
interface IRendererFpsViewProps {
|
||||
renderFps: number;
|
||||
physicsFps: number;
|
||||
}
|
||||
|
||||
@useStatus
|
||||
class RendererFpsView extends Component<IMixinStatusProps, IRendererFpsViewProps> {
|
||||
|
||||
public state = {
|
||||
renderFps: 0,
|
||||
physicsFps: 0,
|
||||
}
|
||||
|
||||
private updateTime: number = 0;
|
||||
|
||||
private renderFpsCalc: (t: number) => void = () => {};
|
||||
private physicsFpsCalc: (t: number) => void = () => {};
|
||||
|
||||
public componentDidMount() {
|
||||
const { status } = this.props;
|
||||
this.renderFpsCalc = this.createFpsCalc("renderFps");
|
||||
this.physicsFpsCalc = this.createFpsCalc("physicsFps");
|
||||
if (status) {
|
||||
status.on("physicsLoop", this.physicsFpsCalc);
|
||||
status.on("renderLoop", this.renderFpsCalc);
|
||||
}
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
const { status } = this.props;
|
||||
if (status) {
|
||||
status.off("physicsLoop", this.physicsFpsCalc);
|
||||
status.off("renderLoop", this.renderFpsCalc);
|
||||
}
|
||||
}
|
||||
|
||||
private createFpsCalc(type: "renderFps" | "physicsFps") {
|
||||
return (t: number) => {
|
||||
if (t === 0) {
|
||||
return;
|
||||
}
|
||||
let newState: IRendererFpsViewProps = {} as any;
|
||||
newState[type] = 1 / t;
|
||||
if (this.updateTime > 20) {
|
||||
this.updateTime = 0;
|
||||
this.setState(newState);
|
||||
}
|
||||
this.updateTime ++;
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
|
||||
const fpsInfo = {
|
||||
renderFps: Math.floor(this.state.renderFps).toString(),
|
||||
physicsFps: Math.floor(this.state.physicsFps).toString()
|
||||
};
|
||||
|
||||
return <Theme
|
||||
className="render-view-fps"
|
||||
fontLevel={FontLevel.normal}
|
||||
>
|
||||
<div className="fps-view">
|
||||
<Localization i18nKey="Header.Bar.Fps.Render.Info" options={{
|
||||
fps: fpsInfo.renderFps
|
||||
}}/><br/>
|
||||
<Localization i18nKey="Header.Bar.Fps.Simulate.Info" options={{
|
||||
fps: fpsInfo.physicsFps
|
||||
}}/>
|
||||
</div>
|
||||
</Theme>;
|
||||
}
|
||||
}
|
||||
|
||||
@useSetting
|
||||
@useStatus
|
||||
class RenderView extends Component<IMixinStatusProps & IMixinSettingProps> {
|
||||
@ -23,12 +99,17 @@ class RenderView extends Component<IMixinStatusProps & IMixinSettingProps> {
|
||||
[190 / 255, 187 / 255, 184 / 255, 1]
|
||||
}
|
||||
|
||||
return <div ref={this.rootEle} className={classList.join(" ")}/>;
|
||||
return <>
|
||||
{
|
||||
this.props.setting?.platform === Platform.desktop ?
|
||||
<RendererFpsView/> : null
|
||||
}
|
||||
<div ref={this.rootEle} className={classList.join(" ")}/>;
|
||||
</>
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
let div = this.rootEle.current;
|
||||
// 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