import { useEffect, useState, type RefObject } from 'react'; import { DEFAULT_VIEWER_DISPLAY_OPTIONS, type ViewerDisplayOptions, } from '../../viewer/displayOptions'; import { dispatchLayoutWidths, type LayoutPreset } from '../components/LayoutSettingsDialog'; import type { WorkspaceTool } from '../components/WorkspaceToolsPanel'; import { useSidebarLayout } from './useSidebarLayout'; import { useThemePreference } from './useThemePreference'; function initialDisplayOptions(): ViewerDisplayOptions { try { const stored = JSON.parse( localStorage.getItem('mujoco-platform-display') ?? 'null', ) as Partial | null; if (!stored) return { ...DEFAULT_VIEWER_DISPLAY_OPTIONS }; const next = { ...DEFAULT_VIEWER_DISPLAY_OPTIONS }; for (const key of Object.keys(next) as (keyof ViewerDisplayOptions)[]) if (typeof stored[key] === 'boolean') next[key] = stored[key]; return next; } catch { return { ...DEFAULT_VIEWER_DISPLAY_OPTIONS }; } } /** 仅持有工作台界面状态;不加载模型、不创建 Viewer、不持有物理时钟。 */ export function useWorkbenchChrome(root: RefObject) { const sidebars = useSidebarLayout(); const { setLeftOpen, setRightOpen } = sidebars; const [theme, setTheme] = useThemePreference(); const [forceScale, setForceScale] = useState(50), [helpOpen, setHelpOpen] = useState(false), [commandOpen, setCommandOpen] = useState(false), [sourceOpen, setSourceOpen] = useState(false), [removeConfirmOpen, setRemoveConfirmOpen] = useState(false), [fullscreen, setFullscreen] = useState(false), [settingsOpen, setSettingsOpen] = useState(false), [layoutOpen, setLayoutOpen] = useState(false), [diagnosticsOpen, setDiagnosticsOpen] = useState(false), [workspaceTool, setWorkspaceTool] = useState(null), [displayOptions, setDisplayOptions] = useState(initialDisplayOptions), [showSensorCamera, setShowSensorCamera] = useState(true), [jointAdvanced, setJointAdvanced] = useState(false), [angleUnit, setAngleUnit] = useState<'rad' | 'deg'>('rad'); useEffect(() => { const change = () => setFullscreen(document.fullscreenElement === root.current); document.addEventListener('fullscreenchange', change); return () => document.removeEventListener('fullscreenchange', change); }, [root]); const toggleFullscreen = () => { if (document.fullscreenElement) void document.exitFullscreen().catch(() => {}); else if (root.current) void root.current.requestFullscreen().catch(() => {}); }; const showWorkspaceTool = (tool: WorkspaceTool) => { setWorkspaceTool(tool); setRightOpen(true); }; const applyLayoutPreset = (preset: LayoutPreset) => { if (preset === 'viewport') { setLeftOpen(false); setRightOpen(false); dispatchLayoutWidths(288, 288); } else if (preset === 'project') { setLeftOpen(true); setRightOpen(false); dispatchLayoutWidths(384, 288); } else if (preset === 'control') { setLeftOpen(false); setRightOpen(true); setWorkspaceTool('controls'); dispatchLayoutWidths(288, 384); } else { setLeftOpen(true); setRightOpen(true); dispatchLayoutWidths(288, 288); } }; return { ...sidebars, theme, setTheme, forceScale, setForceScale, helpOpen, setHelpOpen, commandOpen, setCommandOpen, sourceOpen, setSourceOpen, removeConfirmOpen, setRemoveConfirmOpen, fullscreen, toggleFullscreen, settingsOpen, setSettingsOpen, layoutOpen, setLayoutOpen, diagnosticsOpen, setDiagnosticsOpen, workspaceTool, setWorkspaceTool, showWorkspaceTool, displayOptions, setDisplayOptions, showSensorCamera, setShowSensorCamera, jointAdvanced, setJointAdvanced, angleUnit, setAngleUnit, applyLayoutPreset, }; }