diff --git a/nerfstudio/viewer/app/src/modules/ConfigPanel/ConfigPanel.jsx b/nerfstudio/viewer/app/src/modules/ConfigPanel/ConfigPanel.jsx index 66b92458e..5b20b545e 100644 --- a/nerfstudio/viewer/app/src/modules/ConfigPanel/ConfigPanel.jsx +++ b/nerfstudio/viewer/app/src/modules/ConfigPanel/ConfigPanel.jsx @@ -1,6 +1,8 @@ -import { buttonGroup, useControls } from 'leva'; +import * as React from 'react'; +import { Leva, buttonGroup, useControls } from 'leva'; import { useContext, useEffect, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; +import LevaTheme from '../../themes/leva_theme.json'; import { WebSocketContext } from '../WebSocket/WebSocket'; @@ -22,7 +24,7 @@ function dispatch_and_send(websocket, dispatch, path, data) { } } -export function RenderControls() { +function ControlsLeva() { // connection status indicators const websocket = useContext(WebSocketContext).socket; const outputOptions = useSelector( @@ -326,3 +328,18 @@ export function RenderControls() { return null; } + +export function RenderControls() { + return ( +
+ + +
+ ); +} diff --git a/nerfstudio/viewer/app/src/modules/SidePanel/ExportPanel/ExportPanel.jsx b/nerfstudio/viewer/app/src/modules/SidePanel/ExportPanel/ExportPanel.jsx index 51617dfc8..30e390b34 100644 --- a/nerfstudio/viewer/app/src/modules/SidePanel/ExportPanel/ExportPanel.jsx +++ b/nerfstudio/viewer/app/src/modules/SidePanel/ExportPanel/ExportPanel.jsx @@ -49,7 +49,7 @@ const CLIPPING_BOX_NAME = 'Clipping Box'; export default function ExportPanel(props) { // unpack relevant information const sceneTree = props.sceneTree; - const showExportBox = props.showExportBox; + const showExportBox = useSelector((state) => state.show_export_box); const [type_value, setTypeValue] = React.useState(false); diff --git a/nerfstudio/viewer/app/src/modules/SidePanel/SidePanel.jsx b/nerfstudio/viewer/app/src/modules/SidePanel/SidePanel.jsx index 35dd126d6..292c88a85 100644 --- a/nerfstudio/viewer/app/src/modules/SidePanel/SidePanel.jsx +++ b/nerfstudio/viewer/app/src/modules/SidePanel/SidePanel.jsx @@ -5,19 +5,16 @@ import * as THREE from 'three'; import Box from '@mui/material/Box'; import Divider from '@mui/material/Divider'; -import { Leva } from 'leva'; import Tab from '@mui/material/Tab'; import Tabs from '@mui/material/Tabs'; -import Typography from '@mui/material/Typography'; import { CameraAltRounded, TuneRounded, WidgetsRounded, ImportExportRounded, } from '@mui/icons-material/'; -import { useSelector } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import StatusPanel from './StatusPanel'; -import LevaTheme from '../../themes/leva_theme.json'; import CameraPanel from './CameraPanel'; import ScenePanel from './ScenePanel'; import { RenderControls } from '../ConfigPanel/ConfigPanel'; @@ -39,31 +36,6 @@ export const snap_to_camera = (sceneTree, camera, matrix) => { ); }; -interface TabPanelProps { - children: React.ReactNode; - index: number; - value: number; -} - -function TabPanel(props: TabPanelProps) { - const { children, value, index, ...other } = props; - - return ( - - ); -} - function a11yProps(index: number) { return { id: `simple-tab-${index}`, @@ -71,6 +43,86 @@ function a11yProps(index: number) { }; } +interface PanelTabContentsProps { + children: React.ReactNode; + index: number; + value: number; +} + +/** One tab in the control panel. */ +function PanelTabContents(props: PanelTabContentsProps) { + const { children, value, index, ...other } = props; + + return ( + + ); +} + +interface PanelContentsProps { + children: React.ReactNode; +} + +function PanelContents(props: PanelContentsProps) { + const dispatch = useDispatch(); + const [tabState, setTabState] = React.useState(0); + const handleChange = (_event: React.SyntheticEvent, newValue: number) => { + setTabState(newValue); + dispatch({ + type: 'write', + path: 'show_export_box', + data: newValue === 3, + }); + }; + const camera_choice = useSelector( + (state) => state.renderingState.camera_choice, + ); + const arrayChildren = React.Children.toArray(props.children); + + return ( + <> + + + } label="Controls" {...a11yProps(0)} /> + } label="Render" {...a11yProps(1)} /> + } + label="Scene" + disabled={camera_choice === 'Render Camera'} + {...a11yProps(2)} + /> + } + label="Export" + disabled={camera_choice === 'Render Camera'} + {...a11yProps(3)} + /> + + + + {arrayChildren.map((child, index) => ( + // eslint-disable-next-line react/no-array-index-key + + {child} + + ))} + + ); +} + interface BasicTabsProps { sceneTree: object; } @@ -78,78 +130,17 @@ interface BasicTabsProps { export function BasicTabs(props: BasicTabsProps) { const sceneTree = props.sceneTree; - const [value, setValue] = React.useState(0); - const [showExportBox, setShowExportBox] = React.useState(false); - - const handleChange = (event: React.SyntheticEvent, newValue: number) => { - setValue(newValue); - setShowExportBox(newValue === 3); - }; - const camera_choice = useSelector( - (state) => state.renderingState.camera_choice, - ); - - React.useEffect(() => { - if (camera_choice === 'Render Camera') { - setValue(1); - } - }, [camera_choice]); - return (
- - - } label="Controls" {...a11yProps(0)} /> - } label="Render" {...a11yProps(1)} /> - } - label="Scene" - disabled={camera_choice === 'Render Camera'} - {...a11yProps(2)} - /> - } - label="Export" - disabled={camera_choice === 'Render Camera'} - {...a11yProps(3)} - /> - - - -
- - -
-
- - - - -
- -
-
- - - - + + + + + +
); diff --git a/nerfstudio/viewer/app/src/reducer.js b/nerfstudio/viewer/app/src/reducer.js index 5aefe9c8a..21279a547 100644 --- a/nerfstudio/viewer/app/src/reducer.js +++ b/nerfstudio/viewer/app/src/reducer.js @@ -13,6 +13,8 @@ const initialState = { render_img: null, // The rendered images + show_export_box: false, // whether to show the export box + // the rendering state renderingState: { // cameras