From eccd7fdf7c149bec06f1a395e1352da2c0eb4032 Mon Sep 17 00:00:00 2001 From: MrKBear Date: Thu, 14 Apr 2022 17:54:37 +0800 Subject: [PATCH] Add desktop layout --- source/Component/HeaderBar/HeaderBar.scss | 48 +++++++- source/Component/HeaderBar/HeaderBar.tsx | 140 ++++++++++++---------- source/Context/Setting.tsx | 12 +- source/Localization/EN-US.ts | 2 + source/Localization/ZH-CN.ts | 2 + source/Page/SimulatorWeb/SimulatorWeb.tsx | 4 +- source/Panel/RenderView/RenderView.scss | 13 ++ source/Panel/RenderView/RenderView.tsx | 87 +++++++++++++- 8 files changed, 240 insertions(+), 68 deletions(-) diff --git a/source/Component/HeaderBar/HeaderBar.scss b/source/Component/HeaderBar/HeaderBar.scss index 0150667..eb11584 100644 --- a/source/Component/HeaderBar/HeaderBar.scss +++ b/source/Component/HeaderBar/HeaderBar.scss @@ -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); + } + } } \ No newline at end of file diff --git a/source/Component/HeaderBar/HeaderBar.tsx b/source/Component/HeaderBar/HeaderBar.tsx index 6214be8..2be43d2 100644 --- a/source/Component/HeaderBar/HeaderBar.tsx +++ b/source/Component/HeaderBar/HeaderBar.tsx @@ -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 { 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 +
+ + {I18N(this.props, "Header.Bar.Fps", fpsInfo)} +
+
+ } +} + +class HeaderWindowsAction extends Component { + + public render() { + return +
+ +
+
+ +
+
+ +
+
+ } +} + +/** + * 头部信息栏 + */ +@useSettingWithEvent("language") +@useStatusWithEvent("fileChange") +class HeaderBar extends Component { + + 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 - -
- - {I18N(this.props, "Header.Bar.Fps", fpsInfo)} -
-
+ + { + setting?.platform === Platform.desktop ? + : + + } +
} } -export default HeaderBar; export { HeaderBar }; \ No newline at end of file diff --git a/source/Context/Setting.tsx b/source/Context/Setting.tsx index 2684e21..5996ff4 100644 --- a/source/Context/Setting.tsx +++ b/source/Context/Setting.tsx @@ -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 { + /** + * 程序平台 + */ + public platform: Platform = Platform.web; + /** * 主题 */ @@ -63,5 +73,5 @@ const useSettingWithEvent = superConnectWithEvent(Setti export { Themes, Setting, SettingContext, useSetting, Language, useSettingWithEvent, - IMixinSettingProps, SettingProvider, SettingConsumer + IMixinSettingProps, SettingProvider, SettingConsumer, Platform }; \ No newline at end of file diff --git a/source/Localization/EN-US.ts b/source/Localization/EN-US.ts index a9edf6f..cba84c0 100644 --- a/source/Localization/EN-US.ts +++ b/source/Localization/EN-US.ts @@ -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", diff --git a/source/Localization/ZH-CN.ts b/source/Localization/ZH-CN.ts index 11a40eb..f44fbc4 100644 --- a/source/Localization/ZH-CN.ts +++ b/source/Localization/ZH-CN.ts @@ -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": "拖拽进行视角移动", diff --git a/source/Page/SimulatorWeb/SimulatorWeb.tsx b/source/Page/SimulatorWeb/SimulatorWeb.tsx index 281cac4..b8ef191 100644 --- a/source/Page/SimulatorWeb/SimulatorWeb.tsx +++ b/source/Page/SimulatorWeb/SimulatorWeb.tsx @@ -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(); diff --git a/source/Panel/RenderView/RenderView.scss b/source/Panel/RenderView/RenderView.scss index f174294..ef4c361 100644 --- a/source/Panel/RenderView/RenderView.scss +++ b/source/Panel/RenderView/RenderView.scss @@ -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; + } } \ No newline at end of file diff --git a/source/Panel/RenderView/RenderView.tsx b/source/Panel/RenderView/RenderView.tsx index e61c491..c4cf8ec 100644 --- a/source/Panel/RenderView/RenderView.tsx +++ b/source/Panel/RenderView/RenderView.tsx @@ -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 { + + 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 +
+
+ +
+
; + } +} + @useSetting @useStatus class RenderView extends Component { @@ -23,12 +99,17 @@ class RenderView extends Component { [190 / 255, 187 / 255, 184 / 255, 1] } - return
; + return <> + { + this.props.setting?.platform === Platform.desktop ? + : null + } +
; + } 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); }