feat: add settings dialog with render mode selection
- Add SettingDialogManager with radio-style render mode picker (simple/balance/advanced) - Add getRenderMode/setRenderMode API to Engine and EngineManager layers - Wire setting toolbar button to toggle the settings dialog - Add i18n keys for settings dialog (zh-CN/en-US) - Add version display at bottom-right of engine wrapper - Bump version to 1.1.7, rebuild and sync demo libs
This commit is contained in:
@@ -22,3 +22,17 @@
|
||||
left: 20px !important;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
|
||||
.bim-engine-version {
|
||||
position: absolute;
|
||||
bottom: 6px;
|
||||
right: 10px;
|
||||
font-size: 11px;
|
||||
color: rgba(0, 0, 0, 0.25);
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
z-index: 1;
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
letter-spacing: 0.3px;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
declare const __APP_VERSION__: string;
|
||||
import './bim-engine.css';
|
||||
import { ToolbarManager } from './managers/toolbar-manager';
|
||||
import { ButtonGroupManager } from './managers/button-group-manager';
|
||||
@@ -12,6 +13,7 @@ import { SectionAxisDialogManager } from './managers/section-axis-dialog-manager
|
||||
import { SectionBoxDialogManager } from './managers/section-box-dialog-manager';
|
||||
import { WalkControlManager } from './managers/walk-control-manager';
|
||||
import { EngineInfoDialogManager } from './managers/engine-info-dialog-manager';
|
||||
import { SettingDialogManager } from './managers/setting-dialog-manager';
|
||||
import { ComponentDetailManager } from './managers/component-detail-manager';
|
||||
import { AiChatManager } from './managers/ai-chat-manager';
|
||||
import type { EngineOptions, ModelLoadOptions } from './components/engine';
|
||||
@@ -44,6 +46,7 @@ export class BimEngine {
|
||||
public engineInfo: EngineInfoDialogManager | null = null;
|
||||
public componentDetail: ComponentDetailManager | null = null;
|
||||
public aiChat: AiChatManager | null = null;
|
||||
public setting: SettingDialogManager | null = null;
|
||||
|
||||
constructor(
|
||||
container: HTMLElement | string,
|
||||
@@ -100,6 +103,11 @@ export class BimEngine {
|
||||
this.wrapper.className = 'bim-engine-wrapper';
|
||||
this.container.appendChild(this.wrapper);
|
||||
|
||||
const versionEl = document.createElement('div');
|
||||
versionEl.className = 'bim-engine-version';
|
||||
versionEl.textContent = `v${__APP_VERSION__}`;
|
||||
this.wrapper.appendChild(versionEl);
|
||||
|
||||
this.registry.container = this.container;
|
||||
this.registry.wrapper = this.wrapper;
|
||||
|
||||
@@ -141,6 +149,10 @@ export class BimEngine {
|
||||
this.registry.aiChat = this.aiChat;
|
||||
this.aiChat.init();
|
||||
|
||||
this.setting = new SettingDialogManager(this.registry);
|
||||
this.registry.setting = this.setting;
|
||||
this.setting.init();
|
||||
|
||||
this.updateTheme(themeManager.getTheme());
|
||||
themeManager.subscribe((theme) => {
|
||||
this.updateTheme(theme);
|
||||
@@ -166,6 +178,7 @@ export class BimEngine {
|
||||
this.sectionBox?.destroy();
|
||||
this.walkControl?.destroy();
|
||||
this.aiChat?.destroy();
|
||||
this.setting?.destroy();
|
||||
this.container.innerHTML = '';
|
||||
this.registry.reset();
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { ButtonConfig } from '../../../index.type';
|
||||
import { getIcon } from '../../../../../utils/icon-manager';
|
||||
import type { ManagerRegistry } from '../../../../../core/manager-registry';
|
||||
|
||||
export const createSettingButton = (_registry?: ManagerRegistry): ButtonConfig => {
|
||||
export const createSettingButton = (registry?: ManagerRegistry): ButtonConfig => {
|
||||
return {
|
||||
id: 'setting',
|
||||
groupId: 'group-2',
|
||||
@@ -10,8 +10,8 @@ export const createSettingButton = (_registry?: ManagerRegistry): ButtonConfig =
|
||||
label: 'toolbar.setting',
|
||||
icon: getIcon('设置'),
|
||||
keepActive: false,
|
||||
onClick: (button) => {
|
||||
console.log('设置按钮被点击:', button.id);
|
||||
onClick: (_button) => {
|
||||
registry?.setting?.toggle();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -557,6 +557,33 @@ export class Engine implements IBimComponent {
|
||||
|
||||
// ==================== 结束:剖切功能 ====================
|
||||
|
||||
// ==================== 渲染模式 ====================
|
||||
|
||||
/**
|
||||
* 获取当前渲染模式
|
||||
* @returns 'simple' | 'balance' | 'advanced'
|
||||
*/
|
||||
public getRenderMode(): string {
|
||||
if (!this._isInitialized || !this.engine?.engineModelModule) {
|
||||
return 'balance';
|
||||
}
|
||||
return this.engine.engineModelModule.getCurrentMode();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置渲染模式
|
||||
* @param mode 'simple'(性能模式) | 'balance'(平衡模式) | 'advanced'(效果模式)
|
||||
*/
|
||||
public setRenderMode(mode: 'simple' | 'balance' | 'advanced'): void {
|
||||
if (!this._isInitialized || !this.engine?.engineModelModule) {
|
||||
console.warn('[Engine] Cannot set render mode: engine not initialized.');
|
||||
return;
|
||||
}
|
||||
this.engine.engineModelModule.setMode(mode);
|
||||
}
|
||||
|
||||
// ==================== 结束:渲染模式 ====================
|
||||
|
||||
// ==================== 漫游功能 ====================
|
||||
|
||||
/** 漫游模式是否激活 */
|
||||
|
||||
@@ -20,6 +20,7 @@ import type { SectionBoxDialogManager } from '../managers/section-box-dialog-man
|
||||
import type { WalkPathDialogManager } from '../managers/walk-path-dialog-manager';
|
||||
import type { WalkPlanViewDialogManager } from '../managers/walk-plan-view-dialog-manager';
|
||||
import type { EngineInfoDialogManager } from '../managers/engine-info-dialog-manager';
|
||||
import type { SettingDialogManager } from '../managers/setting-dialog-manager';
|
||||
import type { ComponentDetailManager } from '../managers/component-detail-manager';
|
||||
import type { AiChatManager } from '../managers/ai-chat-manager';
|
||||
|
||||
@@ -69,6 +70,8 @@ export class ManagerRegistry {
|
||||
public componentDetail: ComponentDetailManager | null = null;
|
||||
/** AI 聊天管理器 */
|
||||
public aiChat: AiChatManager | null = null;
|
||||
/** 设置对话框管理器 */
|
||||
public setting: SettingDialogManager | null = null;
|
||||
|
||||
constructor() {}
|
||||
|
||||
@@ -93,6 +96,7 @@ export class ManagerRegistry {
|
||||
this.engineInfo = null;
|
||||
this.componentDetail = null;
|
||||
this.aiChat = null;
|
||||
this.setting = null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -209,5 +209,14 @@ export const enUS: TranslationDictionary = {
|
||||
other: 'Other',
|
||||
otherPlaceholder: 'Enter custom answer',
|
||||
submit: 'Submit'
|
||||
},
|
||||
setting: {
|
||||
dialogTitle: 'Settings',
|
||||
renderMode: 'Render Mode',
|
||||
modes: {
|
||||
simple: 'Performance',
|
||||
balance: 'Balanced',
|
||||
advanced: 'Quality',
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -231,6 +231,15 @@ export interface TranslationDictionary {
|
||||
otherPlaceholder: string;
|
||||
submit: string;
|
||||
};
|
||||
setting: {
|
||||
dialogTitle: string;
|
||||
renderMode: string;
|
||||
modes: {
|
||||
simple: string;
|
||||
balance: string;
|
||||
advanced: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -209,5 +209,14 @@ export const zhCN: TranslationDictionary = {
|
||||
other: '其他',
|
||||
otherPlaceholder: '请输入自定义答案',
|
||||
submit: '提交'
|
||||
},
|
||||
setting: {
|
||||
dialogTitle: '设置',
|
||||
renderMode: '渲染模式',
|
||||
modes: {
|
||||
simple: '性能模式',
|
||||
balance: '平衡模式',
|
||||
advanced: '效果模式',
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -685,6 +685,26 @@ export class EngineManager extends BaseManager {
|
||||
|
||||
// ==================== 结束:构件操作 ====================
|
||||
|
||||
// ==================== 渲染模式 ====================
|
||||
|
||||
/**
|
||||
* 获取当前渲染模式
|
||||
* @returns 'simple' | 'balance' | 'advanced'
|
||||
*/
|
||||
public getRenderMode(): string {
|
||||
return this.engineInstance?.getRenderMode() ?? 'balance';
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置渲染模式
|
||||
* @param mode 'simple' | 'balance' | 'advanced'
|
||||
*/
|
||||
public setRenderMode(mode: 'simple' | 'balance' | 'advanced'): void {
|
||||
this.engineInstance?.setRenderMode(mode);
|
||||
}
|
||||
|
||||
// ==================== 结束:渲染模式 ====================
|
||||
|
||||
/** 销毁引擎管理器 */
|
||||
public destroy(): void {
|
||||
if (this.engineInstance) {
|
||||
|
||||
107
src/managers/setting-dialog-manager.ts
Normal file
107
src/managers/setting-dialog-manager.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
import { BaseDialogManager } from '../core/base-dialog-manager';
|
||||
import { ManagerRegistry } from '../core/manager-registry';
|
||||
import { t } from '../services/locale';
|
||||
|
||||
type RenderMode = 'simple' | 'balance' | 'advanced';
|
||||
|
||||
export class SettingDialogManager extends BaseDialogManager {
|
||||
protected get dialogId() { return 'setting-dialog'; }
|
||||
protected get dialogTitle() { return 'setting.dialogTitle'; }
|
||||
protected get dialogWidth() { return 280; }
|
||||
|
||||
constructor(registry: ManagerRegistry) {
|
||||
super(registry);
|
||||
}
|
||||
|
||||
public init(): void {}
|
||||
|
||||
protected getDialogPosition() {
|
||||
const container = this.registry.container;
|
||||
if (!container) return { x: 100, y: 100 };
|
||||
|
||||
const containerWidth = container.clientWidth;
|
||||
const containerHeight = container.clientHeight;
|
||||
|
||||
return {
|
||||
x: (containerWidth - this.dialogWidth) / 2,
|
||||
y: (containerHeight - 200) / 2
|
||||
};
|
||||
}
|
||||
|
||||
protected createContent(): HTMLElement {
|
||||
const currentMode = this.registry.engine3d?.getRenderMode() ?? 'balance';
|
||||
|
||||
const content = document.createElement('div');
|
||||
content.style.cssText = 'padding: 16px;';
|
||||
|
||||
// 渲染模式标题
|
||||
const label = document.createElement('div');
|
||||
label.style.cssText = 'font-size: 13px; color: var(--bim-text-secondary, #94a3b8); margin-bottom: 12px;';
|
||||
label.textContent = t('setting.renderMode');
|
||||
content.appendChild(label);
|
||||
|
||||
// 三个模式选项
|
||||
const modes: { key: RenderMode; labelKey: string }[] = [
|
||||
{ key: 'simple', labelKey: 'setting.modes.simple' },
|
||||
{ key: 'balance', labelKey: 'setting.modes.balance' },
|
||||
{ key: 'advanced', labelKey: 'setting.modes.advanced' },
|
||||
];
|
||||
|
||||
const group = document.createElement('div');
|
||||
group.style.cssText = 'display: flex; flex-direction: column; gap: 4px;';
|
||||
|
||||
for (const mode of modes) {
|
||||
const item = document.createElement('div');
|
||||
item.style.cssText = `
|
||||
display: flex; align-items: center; gap: 10px;
|
||||
padding: 10px 12px; border-radius: 6px; cursor: pointer;
|
||||
transition: background 0.15s;
|
||||
background: ${mode.key === currentMode ? 'var(--bim-primary, #3b82f6)' : 'transparent'};
|
||||
color: ${mode.key === currentMode ? 'var(--bim-text-inverse, #fff)' : 'var(--bim-text-primary, #fff)'};
|
||||
`;
|
||||
|
||||
// 圆点指示器
|
||||
const dot = document.createElement('div');
|
||||
dot.style.cssText = `
|
||||
width: 16px; height: 16px; border-radius: 50%; flex-shrink: 0;
|
||||
border: 2px solid ${mode.key === currentMode ? 'var(--bim-text-inverse, #fff)' : 'var(--bim-text-tertiary, #64748b)'};
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
`;
|
||||
if (mode.key === currentMode) {
|
||||
const inner = document.createElement('div');
|
||||
inner.style.cssText = 'width: 8px; height: 8px; border-radius: 50%; background: var(--bim-text-inverse, #fff);';
|
||||
dot.appendChild(inner);
|
||||
}
|
||||
|
||||
const text = document.createElement('span');
|
||||
text.style.cssText = 'font-size: 14px; font-weight: 500;';
|
||||
text.textContent = t(mode.labelKey);
|
||||
|
||||
item.appendChild(dot);
|
||||
item.appendChild(text);
|
||||
|
||||
item.addEventListener('mouseenter', () => {
|
||||
if (mode.key !== currentMode) {
|
||||
item.style.background = 'var(--bim-floating-btn-bg, rgba(255,255,255,0.08))';
|
||||
}
|
||||
});
|
||||
item.addEventListener('mouseleave', () => {
|
||||
if (mode.key !== currentMode) {
|
||||
item.style.background = 'transparent';
|
||||
}
|
||||
});
|
||||
|
||||
item.addEventListener('click', () => {
|
||||
this.registry.engine3d?.setRenderMode(mode.key);
|
||||
// 重新渲染弹窗内容
|
||||
this.hide();
|
||||
this.show();
|
||||
});
|
||||
|
||||
group.appendChild(item);
|
||||
}
|
||||
|
||||
content.appendChild(group);
|
||||
return content;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user