Compare commits
	
		
			4 Commits
		
	
	
		
			bbeaa037ee
			...
			2155824089
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 2155824089 | |||
| 6f8451ea9b | |||
| 19d77dceb0 | |||
| 51931f11fe | 
| @ -1,6 +1,7 @@ | ||||
| import { BackgroundLevel, Theme } from "@Component/Theme/Theme"; | ||||
| import { DirectionalHint, IconButton } from "@fluentui/react"; | ||||
| import { LocalizationTooltipHost } from "../Localization/LocalizationTooltipHost"; | ||||
| import { useSetting, IMixinSettingProps } from "@Context/Setting"; | ||||
| import { AllI18nKeys } from "../Localization/Localization"; | ||||
| import { Component, ReactNode } from "react"; | ||||
| import "./CommandBar.scss"; | ||||
| @ -9,13 +10,19 @@ interface ICommandBarProps { | ||||
|     width: number; | ||||
| } | ||||
| 
 | ||||
| class CommandBar extends Component<ICommandBarProps> { | ||||
| @useSetting | ||||
| class CommandBar extends Component<ICommandBarProps & IMixinSettingProps> { | ||||
| 
 | ||||
|     render(): ReactNode { | ||||
|         return <Theme | ||||
|             className="command-bar" | ||||
|             backgroundLevel={BackgroundLevel.Level2} | ||||
|             style={{ width: this.props.width }} | ||||
|             onClick={() => { | ||||
|                 if (this.props.setting) { | ||||
|                     this.props.setting.layout.focus(""); | ||||
|                 } | ||||
|             }} | ||||
|         > | ||||
|             <div> | ||||
|                 {this.getRenderButton({ iconName: "Save", i18NKey: "Command.Bar.Save.Info" })} | ||||
|  | ||||
| @ -43,6 +43,7 @@ div.app-container { | ||||
| 			box-sizing: border-box; | ||||
| 			display: flex; | ||||
| 			border: .8px solid rgba($color: #000000, $alpha: 0); | ||||
| 			// transition: all 300ms ease-in-out; | ||||
| 			justify-content: space-between; | ||||
| 			align-items: stretch; | ||||
| 			flex-direction: column; | ||||
| @ -63,7 +64,7 @@ div.app-container { | ||||
| 				box-sizing: border-box; | ||||
| 				height: 32.8px; | ||||
| 				border: .8px solid rgba($color: #000000, $alpha: 0); | ||||
| 				transition: all 300ms ease-in-out; | ||||
| 				// transition: all 300ms ease-in-out; | ||||
| 			} | ||||
| 
 | ||||
| 			div.title-view { | ||||
| @ -82,6 +83,7 @@ div.app-container { | ||||
| 
 | ||||
| 		div.app-tab-header-item.active { | ||||
| 			border: .8px solid blue; | ||||
| 			transition: none; | ||||
| 		} | ||||
| 
 | ||||
| 		div.app-tab-header-item::after { | ||||
| @ -92,32 +94,52 @@ div.app-container { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	div.app-panel.has-padding { | ||||
| 		padding: 10px; | ||||
| 	} | ||||
| 
 | ||||
| 	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); | ||||
| 	} | ||||
| 
 | ||||
| 	div.app-panel.hide-scrollbar::-webkit-scrollbar { | ||||
| 		width : 0;  /*高宽分别对应横竖滚动条的尺寸*/ | ||||
| 		height: 0; | ||||
| 	} | ||||
| 	 | ||||
| 	div.app-panel::-webkit-scrollbar { | ||||
| 		width : 8px;  /*高宽分别对应横竖滚动条的尺寸*/ | ||||
|   		height: 0; | ||||
| 	} | ||||
| 
 | ||||
| 	div.app-panel::-webkit-scrollbar-thumb { | ||||
| 		/*滚动条里面小方块*/ | ||||
| 		border-radius: 8px; | ||||
| 	} | ||||
| 
 | ||||
| 	div.app-panel::-webkit-scrollbar-track { | ||||
| 		/*滚动条里面轨道*/ | ||||
| 		border-radius: 8px; | ||||
| 		background-color: rgba($color: #000000, $alpha: 0); | ||||
| 	} | ||||
| 
 | ||||
| 	div.app-panel.active { | ||||
| 		border: .8px solid blue !important; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| div.app-panel { | ||||
| 	overflow: scroll; | ||||
| 	-ms-overflow-style: none; | ||||
| } | ||||
| div.app-panel::-webkit-scrollbar { | ||||
| 	width: 0 !important; | ||||
| 	height: 0 !important; | ||||
| } | ||||
| 
 | ||||
| div.dark.app-container.end-containe { | ||||
| 	border: .8px solid $lt-bg-color-lvl3-dark; | ||||
| 
 | ||||
| 	div.app-tab-header-item.tab, | ||||
| 	div.app-tab-header-item.active, | ||||
| 	div.app-tab-header-item:hover { | ||||
| 		transition: none; | ||||
| 		background-color: $lt-bg-color-lvl4-dark; | ||||
| 		color: rgba($color: #FFFFFF, $alpha: .85); | ||||
| 	} | ||||
| @ -125,21 +147,33 @@ div.dark.app-container.end-containe { | ||||
| 	div.app-tab-header-item.active { | ||||
| 		div.border-view::after { | ||||
| 			background-color: $lt-bg-color-lvl4-dark; | ||||
| 			transition: none; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	div.app-panel::-webkit-scrollbar-thumb { | ||||
| 		background-color: $lt-bg-color-lvl1-dark; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| div.light.app-container.end-containe { | ||||
| 	border: .8px solid $lt-bg-color-lvl3-light; | ||||
| 
 | ||||
| 	div.app-tab-header-item.tab, | ||||
| 	div.app-tab-header-item.active, | ||||
| 	div.app-tab-header-item:hover { | ||||
| 		transition: none; | ||||
| 		color: rgba($color: #000000, $alpha: .85); | ||||
| 	} | ||||
| 
 | ||||
| 	div.app-tab-header-item.active { | ||||
| 		div.border-view::after { | ||||
| 			background-color: $lt-bg-color-lvl4-light; | ||||
| 			transition: none; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	div.app-panel::-webkit-scrollbar-thumb { | ||||
| 		background-color: $lt-bg-color-lvl1-light; | ||||
| 	} | ||||
| } | ||||
| @ -1,7 +1,11 @@ | ||||
| import { Localization } from "@Component/Localization/Localization"; | ||||
| import { Theme, BackgroundLevel, FontLevel } from "@Component/Theme/Theme"; | ||||
| import { Themes } from "@Context/Setting"; | ||||
| import { DirectionalHint } from "@fluentui/react"; | ||||
| import { ILayout, LayoutDirection } from "@Model/Layout"; | ||||
| import { Component, ReactNode } from "react"; | ||||
| import { Component, ReactNode, MouseEvent } from "react"; | ||||
| import { getPanelById, getPanelInfoById } from "../../Panel/Panel"; | ||||
| import { LocalizationTooltipHost } from "../Localization/LocalizationTooltipHost"; | ||||
| import "./Container.scss"; | ||||
| 
 | ||||
| interface IContainerProps extends ILayout { | ||||
| @ -10,17 +14,13 @@ interface IContainerProps extends ILayout { | ||||
| 	theme?: Themes; | ||||
| 	focusId?: string; | ||||
| 	onScaleChange?: (id: number, scale: number) => any; | ||||
| } | ||||
| 
 | ||||
| function getPanelById(id: string) { | ||||
| 	return <Theme | ||||
| 		className="app-panel" draggable={false} | ||||
| 	>{id}</Theme> | ||||
| 	onFocusTab?: (id: string) => any; | ||||
| } | ||||
| 
 | ||||
| class Container extends Component<IContainerProps> { | ||||
| 
 | ||||
| 	private focusEdgeId: number | undefined; | ||||
| 
 | ||||
| 	private readonly edgeInfo = { | ||||
| 		direction: LayoutDirection.Y, | ||||
| 		rootWidth: 0, | ||||
| @ -31,62 +31,83 @@ class Container extends Component<IContainerProps> { | ||||
| 		mouseY: 0 | ||||
| 	}; | ||||
| 
 | ||||
| 	private renderPanel(panles: string[], showBar: boolean) { | ||||
| 	/** | ||||
| 	 * 渲染此 Tab 下的 ELE | ||||
| 	 */ | ||||
| 	private renderPanel(panles: string[], showBar: boolean, focus?: string) { | ||||
| 
 | ||||
| 		const classList: string[] = []; | ||||
| 		const theme: Themes = this.props.theme ?? Themes.dark; | ||||
| 		const showPanelId = focus ?? panles[0]; | ||||
| 		const showPanelInfo = getPanelInfoById(showPanelId as any); | ||||
| 
 | ||||
| 		classList.push(theme === Themes.light ? "light" : "dark"); | ||||
| 		classList.push(`background-${BackgroundLevel.Level3}`); | ||||
| 		classList.push(`font-${FontLevel.Level3}`); | ||||
| 		classList.push("app-tab-header"); | ||||
| 
 | ||||
| 		const hasActivePanel = panles.some((id) => id === this.props.focusId); | ||||
| 
 | ||||
| 		return <> | ||||
| 			{showBar ?  | ||||
| 				<div className={classList.join(" ")} >{ | ||||
| 				<div className={classList.join(" ")} onClick={() => { | ||||
| 					this.props.onFocusTab ? this.props.onFocusTab("") : undefined | ||||
| 				}}>{ | ||||
| 					panles.map((panelId: string) => { | ||||
| 						return <div key={panelId} className="app-tab-header-item"> | ||||
| 
 | ||||
| 						const classList: string[] = ["app-tab-header-item"]; | ||||
| 						if (panelId === this.props.focusId) classList.push("active"); | ||||
| 						if (panelId === showPanelId) classList.push("tab"); | ||||
| 						const panelInfo = getPanelInfoById(panelId as any); | ||||
| 
 | ||||
| 						return <LocalizationTooltipHost | ||||
| 							i18nKey={panelInfo ? panelInfo.introKay as any : "Panel.Info.Notfound"} | ||||
| 							options={{id: panelId}} | ||||
| 							directionalHint={DirectionalHint.topAutoEdge} | ||||
| 							delay={2} | ||||
| 							key={panelId} | ||||
| 						> | ||||
| 							<div	 | ||||
| 								className={classList.join(" ")} | ||||
| 								onClick={(e) => { | ||||
| 									e.stopPropagation(); | ||||
| 									this.props.onFocusTab ? this.props.onFocusTab(panelId) : undefined; | ||||
| 								}} | ||||
| 							> | ||||
| 								<div className="border-view"></div> | ||||
| 							<div className="title-view" >{panelId}</div> | ||||
| 								<div className="title-view"> | ||||
| 									{ | ||||
| 										panelInfo ? | ||||
| 											<Localization i18nKey={panelInfo.nameKey as any}/>: | ||||
| 											<Localization i18nKey="Panel.Title.Notfound" options={{id: panelId}}/> | ||||
| 									} | ||||
| 									 | ||||
| 								</div> | ||||
| 							</div> | ||||
| 						</LocalizationTooltipHost> | ||||
| 					}) | ||||
| 				}</div> : null | ||||
| 			} | ||||
| 			{getPanelById(panles[0])} | ||||
| 			<div | ||||
| 				onClick={() => this.props.onFocusTab ? this.props.onFocusTab(showPanelId) : undefined} | ||||
| 				className={[ | ||||
| 					"app-panel", | ||||
| 					hasActivePanel ? "active" : "", | ||||
| 					showPanelInfo?.hidePadding ? "" : "has-padding", | ||||
| 					showPanelInfo?.hideScrollBar ? "hide-scrollbar" : "" | ||||
| 				].filter(x => !!x).join(" ")} | ||||
| 				draggable={false} | ||||
| 			> | ||||
| 				{getPanelById(showPanelId as any)} | ||||
| 			</div> | ||||
| 		</> | ||||
| 	} | ||||
| 
 | ||||
| 	private renderContainer( | ||||
| 		props: IContainerProps,  | ||||
| 		selfScale: number = 50,  | ||||
| 		selfLayout: LayoutDirection = LayoutDirection.Y | ||||
| 	) { | ||||
| 	/** | ||||
| 	 * 处理鼠标移动数据 | ||||
| 	 */ | ||||
| 	private handelMouseMove = (e: MouseEvent<HTMLDivElement, globalThis.MouseEvent>) => { | ||||
| 
 | ||||
| 		const items: [IContainerProps, IContainerProps] | undefined = props.items; | ||||
| 		const showBar: boolean = props.showBar ?? true; | ||||
| 		const panles: string[] = props.panles ?? []; | ||||
| 		const layout: LayoutDirection = props.layout ?? LayoutDirection.Y; | ||||
| 		const scale: number = props.scale ?? 50; | ||||
| 		const isRoot: boolean = !!props.isRoot; | ||||
| 		const classList: string[] = []; | ||||
| 		const theme: Themes = this.props.theme ?? Themes.dark; | ||||
| 
 | ||||
| 		classList.push(theme === Themes.light ? "light" : "dark"); | ||||
| 		classList.push(`background-${BackgroundLevel.Level4}`); | ||||
| 		classList.push(`font-${FontLevel.normal}`); | ||||
| 		classList.push("app-container"); | ||||
| 		if (panles.length > 0 && !items) classList.push("end-containe"); | ||||
| 
 | ||||
| 		return <div | ||||
| 			className={classList.join(" ")} | ||||
| 			draggable={false} | ||||
| 			style={{ | ||||
| 				transition: "none", | ||||
| 				flexDirection: layout === LayoutDirection.Y ? "column" : undefined, | ||||
| 				width: isRoot ? "100%" : selfLayout === LayoutDirection.X ? `${selfScale}%` : undefined, | ||||
| 				height: isRoot ? "100%" : selfLayout === LayoutDirection.Y ? `${selfScale}%` : undefined | ||||
| 			}} | ||||
| 			onMouseMove={isRoot ? (e) => { | ||||
| 		if (this.props.onScaleChange && this.focusEdgeId !== undefined) { | ||||
| 			e.preventDefault(); | ||||
| 			let mouveDist: number = 0; | ||||
| @ -114,21 +135,15 @@ class Container extends Component<IContainerProps> { | ||||
| 			let newScale = newSize / rootSize; | ||||
| 			this.props.onScaleChange(this.focusEdgeId, newScale * 100); | ||||
| 		} | ||||
| 			} : undefined} | ||||
| 			onMouseUp={isRoot ? () => { | ||||
| 				this.focusEdgeId = undefined; | ||||
| 			} : undefined} | ||||
| 		> | ||||
| 			{panles.length > 0 && !items ? this.renderPanel(panles, showBar) : null} | ||||
| 			{items && items[0] ? this.renderContainer(items[0], scale, layout) : null} | ||||
| 			{items && items[1] ? <div className="drag-bar" style={{ | ||||
| 				width: layout === LayoutDirection.Y ? "100%" : 0, | ||||
| 				height: layout === LayoutDirection.X ? "100%" : 0 | ||||
| 			}}> | ||||
| 				<div | ||||
| 					style={{ cursor: layout === LayoutDirection.Y ? "n-resize" : "e-resize" }} | ||||
| 					onMouseDown={(e) => { | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * 处理鼠标按下事件 | ||||
| 	 * 记录鼠标数据 | ||||
| 	 */ | ||||
| 	private handelMouseDown = (props: ILayout, e: MouseEvent<HTMLDivElement, globalThis.MouseEvent>) => { | ||||
| 		const targetNode = e.target; | ||||
| 
 | ||||
| 		if (targetNode instanceof HTMLDivElement) { | ||||
| 			let root = targetNode.parentNode?.parentNode; | ||||
| 			let firstDiv = targetNode.parentNode?.parentNode?.childNodes[0]; | ||||
| @ -142,13 +157,68 @@ class Container extends Component<IContainerProps> { | ||||
| 		} | ||||
| 		this.edgeInfo.mouseX = e.clientX; | ||||
| 		this.edgeInfo.mouseY = e.clientY; | ||||
| 
 | ||||
| 		this.edgeInfo.direction = props.layout ?? LayoutDirection.Y; | ||||
| 		this.focusEdgeId = props.id ?? 0; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * 递归渲染全部容器 | ||||
| 	 */ | ||||
| 	private renderContainer ( | ||||
| 		props: IContainerProps, selfScale: number = 50, | ||||
| 		selfLayout: LayoutDirection = LayoutDirection.Y | ||||
| 	) { | ||||
| 
 | ||||
| 		const items: [IContainerProps, IContainerProps] | undefined = props.items; | ||||
| 		const showBar: boolean = props.showBar ?? true; | ||||
| 		const panles: string[] = props.panles ?? []; | ||||
| 		const layout: LayoutDirection = props.layout ?? LayoutDirection.Y; | ||||
| 		const scale: number = props.scale ?? 50; | ||||
| 		const isRoot: boolean = !!props.isRoot; | ||||
| 		const classList: string[] = []; | ||||
| 		const theme: Themes = this.props.theme ?? Themes.dark; | ||||
| 		const focusPanel: string | undefined = props.focusPanel; | ||||
| 
 | ||||
| 		classList.push(theme === Themes.light ? "light" : "dark"); | ||||
| 		classList.push(`background-${BackgroundLevel.Level4}`); | ||||
| 		classList.push(`font-${FontLevel.normal}`); | ||||
| 		classList.push("app-container"); | ||||
| 		if (panles.length > 0 && !items) classList.push("end-containe"); | ||||
| 
 | ||||
| 		return <div | ||||
| 			className={classList.join(" ")} | ||||
| 			draggable={false} | ||||
| 			style={{ | ||||
| 				transition: "none", | ||||
| 				flexDirection: layout === LayoutDirection.Y ? "column" : undefined, | ||||
| 				width: isRoot ? "100%" : selfLayout === LayoutDirection.X ? `${selfScale}%` : undefined, | ||||
| 				height: isRoot ? "100%" : selfLayout === LayoutDirection.Y ? `${selfScale}%` : undefined | ||||
| 			}} | ||||
| 					onMouseUp={() => { this.focusEdgeId = undefined }} | ||||
| 			onMouseMove={isRoot ? this.handelMouseMove : undefined} | ||||
| 			onMouseUp={isRoot ? () => this.focusEdgeId = undefined : undefined} | ||||
| 		> | ||||
| 				</div> | ||||
| 			</div> : null} | ||||
| 			{/* 渲染 Panel */} | ||||
| 			{panles.length > 0 && !items ? this.renderPanel(panles, showBar, focusPanel) : null} | ||||
| 
 | ||||
| 			{/* 渲染第一部分 */} | ||||
| 			{items && items[0] ? this.renderContainer(items[0], scale, layout) : null} | ||||
| 
 | ||||
| 			{/* 渲染拖拽条 */} | ||||
| 			{items && items[1] ?  | ||||
| 				<div className="drag-bar" style={{ | ||||
| 					width: layout === LayoutDirection.Y ? "100%" : 0, | ||||
| 					height: layout === LayoutDirection.X ? "100%" : 0 | ||||
| 				}}> | ||||
| 					<div | ||||
| 						style={{ cursor: layout === LayoutDirection.Y ? "n-resize" : "e-resize" }} | ||||
| 						onMouseDown={ this.handelMouseDown.bind(this, props) } | ||||
| 						onMouseUp={() => this.focusEdgeId = undefined } | ||||
| 					/> | ||||
| 				</div> : null | ||||
| 			} | ||||
| 
 | ||||
| 			{/* 渲染第二部分 */} | ||||
| 			{items && items[1] ? this.renderContainer(items[1], 100 - scale, layout) : null} | ||||
| 		</div> | ||||
| 	} | ||||
|  | ||||
| @ -13,6 +13,7 @@ class RootContainer extends Component<IMixinSettingProps> { | ||||
| 		if (this.props.setting) { | ||||
| 			this.props.setting.layout.on("layoutChange", this.handelChange); | ||||
| 			this.props.setting.layout.on("scaleChange", this.handelChange); | ||||
| 			this.props.setting.layout.on("switchTab", this.handelChange); | ||||
| 			this.props.setting.on("themes", this.handelChange); | ||||
| 		} | ||||
| 	} | ||||
| @ -21,6 +22,7 @@ class RootContainer extends Component<IMixinSettingProps> { | ||||
| 		if (this.props.setting) { | ||||
| 			this.props.setting.layout.off("layoutChange", this.handelChange); | ||||
| 			this.props.setting.layout.off("scaleChange", this.handelChange); | ||||
| 			this.props.setting.layout.off("switchTab", this.handelChange); | ||||
| 			this.props.setting.off("themes", this.handelChange); | ||||
| 		} | ||||
| 	} | ||||
| @ -28,6 +30,7 @@ class RootContainer extends Component<IMixinSettingProps> { | ||||
| 	public render(): ReactNode { | ||||
| 		const layoutData = this.props.setting ? this.props.setting.layout.getData() : {}; | ||||
| 		const theme = this.props.setting?.themes ?? Themes.dark; | ||||
| 		const focusId = this.props.setting?.layout.focusId ?? ""; | ||||
| 		return <Container | ||||
| 			scale={layoutData.scale} | ||||
| 			items={layoutData.items} | ||||
| @ -35,7 +38,9 @@ class RootContainer extends Component<IMixinSettingProps> { | ||||
| 			theme={theme} | ||||
| 			isRoot={true} | ||||
| 			onScaleChange={this.props.setting?.layout.setScale} | ||||
| 			onFocusTab={this.props.setting?.layout.focus} | ||||
| 			id={layoutData.id} | ||||
| 			focusId={focusId} | ||||
| 		/> | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -100,6 +100,11 @@ class HeaderBar extends Component< | ||||
|             backgroundLevel={BackgroundLevel.Level1} | ||||
|             fontLevel={FontLevel.Level3} | ||||
|             style={{ height: this.props.height }} | ||||
|             onClick={() => { | ||||
|                 if (this.props.setting) { | ||||
|                     this.props.setting.layout.focus(""); | ||||
|                 } | ||||
|             }} | ||||
|         > | ||||
|             <LocalizationTooltipHost i18nKey="Header.Bar.Title.Info"> | ||||
|                 <div className="title"> | ||||
|  | ||||
| @ -20,6 +20,10 @@ abstract class BasicRenderer< | ||||
|     E extends Record<EventType, any> = {} | ||||
| > extends AbstractRenderer<P, M & IRendererParams, E & {loop: number}> { | ||||
| 
 | ||||
|     public get dom() { | ||||
|         return this.canvas.dom | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| 	 * 渲染器参数 | ||||
| 	 */ | ||||
|  | ||||
| @ -19,5 +19,10 @@ const EN_US = { | ||||
|     "Command.Bar.Add.Tag.Info": "Add label object", | ||||
|     "Command.Bar.Camera.Info": "Renderer settings", | ||||
|     "Command.Bar.Setting.Info": "Global Settings", | ||||
|     "Panel.Title.Notfound": "{id}", | ||||
|     "Panel.Info.Notfound": "This panel with id {id} can not found!", | ||||
|     "Panel.Title.Render.View": "Live preview", | ||||
|     "Panel.Info.Render.View": "Live simulation results preview", | ||||
| 
 | ||||
| } | ||||
| export default EN_US; | ||||
| @ -19,5 +19,9 @@ const ZH_CN = { | ||||
|     "Command.Bar.Add.Tag.Info": "添加标签对象", | ||||
|     "Command.Bar.Camera.Info": "渲染器设置", | ||||
|     "Command.Bar.Setting.Info": "全局设置", | ||||
|     "Panel.Title.Notfound": "找不到面板: {id}", | ||||
|     "Panel.Info.Notfound": "这个编号为 {id} 的面板无法找到!", | ||||
|     "Panel.Title.Render.View": "实时预览", | ||||
|     "Panel.Info.Render.View": "实时仿真结果预览", | ||||
| } | ||||
| export default ZH_CN; | ||||
| @ -8,6 +8,7 @@ enum LayoutDirection { | ||||
| class ILayout { | ||||
| 	items?: [ILayout, ILayout]; | ||||
| 	panles?: string[]; | ||||
| 	focusPanel?: string; | ||||
| 	layout?: LayoutDirection; | ||||
| 	scale?: number; | ||||
| 	id?: number; | ||||
| @ -16,6 +17,7 @@ class ILayout { | ||||
| interface ILayoutEvent { | ||||
| 	layoutChange: Layout; | ||||
| 	scaleChange: Layout; | ||||
| 	switchTab: Layout; | ||||
| } | ||||
| 
 | ||||
| class Layout extends Emitter<ILayoutEvent> { | ||||
| @ -24,6 +26,11 @@ class Layout extends Emitter<ILayoutEvent> { | ||||
| 
 | ||||
| 	private data: ILayout = {}; | ||||
| 
 | ||||
| 	/** | ||||
|      * 焦点面板 ID | ||||
|      */ | ||||
| 	public focusId: string = ""; | ||||
| 
 | ||||
| 	private map(fn: (layout: ILayout) => boolean | void, layout?: ILayout) { | ||||
| 		const currentLayout = layout ? layout : this.data; | ||||
| 		if( fn(currentLayout) ) return; | ||||
| @ -44,6 +51,9 @@ class Layout extends Emitter<ILayoutEvent> { | ||||
| 		this.id = 0; | ||||
| 		this.map((layout) => { | ||||
| 			layout.id = this.id; | ||||
| 			if (!layout.focusPanel && layout.panles && layout.panles.length > 0) { | ||||
| 				layout.focusPanel = layout.panles[0] | ||||
| 			} | ||||
| 			this.id ++; | ||||
| 		}); | ||||
| 		this.emit("layoutChange", this); | ||||
| @ -62,6 +72,31 @@ class Layout extends Emitter<ILayoutEvent> { | ||||
| 			this.emit("scaleChange", this); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public focus = (panelId: string) => { | ||||
| 		if (panelId === "") { | ||||
| 			this.focusId = panelId; | ||||
| 			this.emit("switchTab", this); | ||||
| 		} | ||||
| 
 | ||||
| 		this.map((layout) => { | ||||
| 			if (layout.panles && layout.panles.length > 0) { | ||||
| 				let index = -1; | ||||
| 				for (let i = 0; i < layout.panles.length; i++) { | ||||
| 					if (layout.panles[i] === panelId) { | ||||
| 						index = i; | ||||
| 						break; | ||||
| 					} | ||||
| 				} | ||||
| 				if (index >= 0) { | ||||
| 					layout.focusPanel = panelId; | ||||
| 					this.focusId = panelId; | ||||
| 					this.emit("switchTab", this); | ||||
| 					return true; | ||||
| 				} | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| export { Layout, ILayout, LayoutDirection }; | ||||
| @ -67,6 +67,8 @@ abstract class AbstractRenderer< | ||||
| 	E extends AbstractRendererEvent = {loop: number} | ||||
| > extends Emitter<E> { | ||||
| 
 | ||||
| 	abstract dom: HTMLDivElement | HTMLCanvasElement; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * 渲染器参数 | ||||
| 	 */ | ||||
|  | ||||
| @ -60,7 +60,7 @@ class SimulatorWeb extends Component { | ||||
|             items: [ | ||||
|                 { | ||||
|                     items: [ | ||||
|                         {panles: ["Label A", "Label Aa Bb", "Label aaa"]}, | ||||
|                         {panles: ["RenderView", "Label Aa Bb", "Label aaa"]}, | ||||
|                         { | ||||
|                             items: [{panles: ["Label b", "Label bbb"]}, {panles: ["C"]}], | ||||
|                             scale: 80, | ||||
|  | ||||
							
								
								
									
										43
									
								
								source/Panel/Panel.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								source/Panel/Panel.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,43 @@ | ||||
| import { ReactNode, Component, FunctionComponent } from "react"; | ||||
| import { Theme } from "@Component/Theme/Theme"; | ||||
| import { Localization } from "@Component/Localization/Localization"; | ||||
| import { RenderView } from "./RenderView/RenderView"; | ||||
| 
 | ||||
| interface IPanelInfo { | ||||
| 	nameKey: string; | ||||
| 	introKay: string; | ||||
| 	class: (new (...p: any) => Component) | FunctionComponent; | ||||
| 	hidePadding?: boolean; | ||||
| 	hideScrollBar?: boolean; | ||||
| 	option?: Record<string, string>; | ||||
| } | ||||
| 
 | ||||
| type PanelId = "" | ||||
| | "RenderView" // 主渲染器
 | ||||
| ; | ||||
| 
 | ||||
| const PanelInfoMap = new Map<PanelId, IPanelInfo>(); | ||||
| PanelInfoMap.set("RenderView", {  | ||||
| 	nameKey: "Panel.Title.Render.View", introKay: "Panel.Info.Render.View", class: RenderView, hidePadding: true, hideScrollBar: true | ||||
| }); | ||||
| 
 | ||||
| function getPanelById(panelId: PanelId): ReactNode { | ||||
| 	switch (panelId) { | ||||
| 		default:  | ||||
| 			let info = PanelInfoMap.get(panelId); | ||||
| 			if (info) { | ||||
| 				const C = info.class; | ||||
| 				return <C></C> | ||||
| 			} else return <Theme> | ||||
| 				<Localization i18nKey={"Panel.Info.Notfound"} options={{ | ||||
| 					id: panelId | ||||
| 				}}/> | ||||
| 			</Theme> | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function getPanelInfoById(panelId: PanelId): IPanelInfo | undefined { | ||||
| 	return PanelInfoMap.get(panelId); | ||||
| } | ||||
| 
 | ||||
| export { PanelId, getPanelById, getPanelInfoById} | ||||
							
								
								
									
										9
									
								
								source/Panel/RenderView/RenderView.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								source/Panel/RenderView/RenderView.scss
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| div.render-view { | ||||
| 	width: 100%; | ||||
| 	height: 100%; | ||||
| 
 | ||||
| 	div.canvas { | ||||
| 		width: 100%; | ||||
| 		height: 100%; | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										38
									
								
								source/Panel/RenderView/RenderView.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								source/Panel/RenderView/RenderView.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | ||||
| import { Component, ReactNode, createRef } from "react"; | ||||
| import { useStatus, IMixinStatusProps } from "@Context/Status"; | ||||
| import { useSetting, IMixinSettingProps, Themes } from "@Context/Setting"; | ||||
| import { ClassicRenderer } from "@GLRender/ClassicRenderer"; | ||||
| import "./RenderView.scss"; | ||||
| 
 | ||||
| @useSetting | ||||
| @useStatus | ||||
| class RenderView extends Component<IMixinStatusProps & IMixinSettingProps> { | ||||
| 
 | ||||
| 	private rootEle = createRef<HTMLDivElement>(); | ||||
| 
 | ||||
| 	public render(): ReactNode { | ||||
| 		const theme = this.props.setting?.themes ?? Themes.dark; | ||||
| 		const classList: string[] = ["render-view", "background-lvl5"]; | ||||
| 		if (theme === Themes.light) classList.push("light"); | ||||
| 		if (theme === Themes.dark) classList.push("dark"); | ||||
| 
 | ||||
| 		if (this.props.status) { | ||||
| 			(this.props.status.renderer as ClassicRenderer).cleanColor =  | ||||
| 			(theme === Themes.dark) ? | ||||
| 				[27 / 255, 26 / 255, 25 / 255, 1] : | ||||
| 				[190 / 255, 187 / 255, 184 / 255, 1] | ||||
| 		} | ||||
| 
 | ||||
| 		return <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); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| export { RenderView } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user