Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion public/locales/en/panel-navigation.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@
"title": "Navigation Settings",
"include-non-focusable-label": "Include Non-focusable Nodes in Search",
"include-non-focusable-description": "Per default, nodes that are marked as non-focusable from the search in the navigation menu. Checking this option will include them and allow setting these nodes as focus.",
"camera-path-settings": "Camera Path Settings"
"camera-path-settings": "Camera Path Settings",
"override-fly-to-duration-label": "Override Fly-to Duration"
},
"remaining-flight-time-indicator": {
"flying-to": "Flying to {{target}}",
Expand Down
6 changes: 6 additions & 0 deletions src/components/NodeNavigationButton/NodeNavigationButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
FrameFocusIcon,
LightningFlashIcon
} from '@/icons/icons';
import { useAppSelector } from '@/redux/hooks';
import { NavigationType } from '@/types/enums';
import { Identifier } from '@/types/types';

Expand Down Expand Up @@ -81,6 +82,9 @@ export function NodeNavigationButton({

const engineMode = useSubscribeToEngineMode();
const luaApi = useOpenSpaceApi();
const flyToOverrideDuration = useAppSelector(
(state) => state.local.menus.navigation.flyToOverrideDuration
);

const isInPlayback = engineMode === EngineMode.SessionRecordingPlayback;

Expand All @@ -95,6 +99,8 @@ export function NodeNavigationButton({
function flyTo(event: React.MouseEvent<HTMLButtonElement, MouseEvent>) {
if (event.shiftKey) {
luaApi?.navigation.flyTo(identifier, 0.0);
} else if (flyToOverrideDuration.enabled) {
luaApi?.navigation.flyTo(identifier, flyToOverrideDuration.duration);
} else {
luaApi?.navigation.flyTo(identifier);
}
Expand Down
60 changes: 58 additions & 2 deletions src/panels/NavigationPanel/NavigationSettings.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,25 @@
import { useTranslation } from 'react-i18next';
import { Container, Divider, Menu } from '@mantine/core';
import {
Box,
Checkbox,
Container,
Divider,
Group,
Menu,
NumberInput,
Stack
} from '@mantine/core';

import { BoolInput } from '@/components/Input/BoolInput';
import { NumericSlider } from '@/components/Input/NumericInput/NumericSlider/NumericSlider';
import { Property } from '@/components/Property/Property';
import { SettingsPopout } from '@/components/SettingsPopout/SettingsPopout';
import { useAppDispatch, useAppSelector } from '@/redux/hooks';
import { setOnlyFocusableInNavMenu } from '@/redux/local/localSlice';
import {
setFlyToOverrideDuration,
setFlyToOverrideDurationEnabled,
setOnlyFocusableInNavMenu
} from '@/redux/local/localSlice';
import {
ApplyIdleMotionOnPathFinishKey,
CameraPathArrivalDistanceFactorKey,
Expand All @@ -20,6 +34,10 @@ export function NavigationSettings() {
(state) => state.local.menus.navigation.onlyFocusable
);

const flyToOverrideDuration = useAppSelector(
(state) => state.local.menus.navigation.flyToOverrideDuration
);

const dispatch = useAppDispatch();

return (
Expand All @@ -40,6 +58,44 @@ export function NavigationSettings() {
<Property uri={CameraPathSpeedFactorKey} />
<Property uri={CameraPathArrivalDistanceFactorKey} />
<Property uri={ApplyIdleMotionOnPathFinishKey} />
<Stack gap={'xs'} mt={'xs'}>
<Checkbox
label={t('override-fly-to-duration-label')}
checked={flyToOverrideDuration.enabled}
onChange={(event) =>
dispatch(setFlyToOverrideDurationEnabled(event.currentTarget.checked))
}
/>
<Group gap={'xs'} wrap={'nowrap'} align={'center'}>
<Box style={{ flex: 1 }}>
<NumericSlider
min={0}
max={60}
step={0.25}
value={flyToOverrideDuration.duration}
disabled={!flyToOverrideDuration.enabled}
onInput={(value) => dispatch(setFlyToOverrideDuration(value))}
/>
</Box>
<NumberInput
size={'xs'}
w={70}
min={0}
max={60}
step={1.25}
clampBehavior={'strict'}
suffix={'s'}
disabled={!flyToOverrideDuration.enabled}
value={flyToOverrideDuration.duration}
onChange={(value) => {
if (typeof value !== 'number' || Number.isNaN(value)) {
return;
}
dispatch(setFlyToOverrideDuration(value));
}}
/>
Comment thread
Copilot marked this conversation as resolved.
</Group>
</Stack>
</Container>
</SettingsPopout>
);
Expand Down
20 changes: 19 additions & 1 deletion src/redux/local/localSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ export interface LocalState {
navigation: {
// Whether to show non-focusable nodes in the navigation menu search results
onlyFocusable: boolean;
flyToOverrideDuration: {
enabled: boolean;
duration: number;
};
};
};
sceneTree: {
Expand All @@ -24,7 +28,11 @@ export interface LocalState {
const initialState: LocalState = {
menus: {
navigation: {
onlyFocusable: true
onlyFocusable: true,
flyToOverrideDuration: {
enabled: false,
duration: 5
}
}
},
// @TODO: (emmbr 2025-04-09): Consider moving this to the menus object above. did not
Expand Down Expand Up @@ -74,6 +82,14 @@ export const localSlice = createSlice({
state.menus.navigation.onlyFocusable = action.payload;
return state;
},
setFlyToOverrideDurationEnabled: (state, action: PayloadAction<boolean>) => {
state.menus.navigation.flyToOverrideDuration.enabled = action.payload;
return state;
},
setFlyToOverrideDuration: (state, action: PayloadAction<number>) => {
state.menus.navigation.flyToOverrideDuration.duration = action.payload;
return state;
},
setMenuItemVisible: (
state,
action: PayloadAction<{ id: string; visible: boolean }>
Expand Down Expand Up @@ -108,6 +124,8 @@ export const {
setSceneTreeNodeExpanded,
setSceneTreeSelectedNode,
setOnlyFocusableInNavMenu,
setFlyToOverrideDurationEnabled,
setFlyToOverrideDuration,
setMenuItemVisible,
setMenuItemOpen,
setMenuItemsConfig,
Expand Down
Loading