diff --git a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-Inch-scale-1-Google-Chrome-linux.png b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-Inch-scale-1-Google-Chrome-linux.png index 2b08d071b..4fcb405f8 100644 Binary files a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-Inch-scale-1-Google-Chrome-linux.png and b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-Inch-scale-1-Google-Chrome-linux.png differ diff --git a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-Millimeter-scale-1-Google-Chrome-linux.png b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-Millimeter-scale-1-Google-Chrome-linux.png index 3a7f86a60..51c570784 100644 Binary files a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-Millimeter-scale-1-Google-Chrome-linux.png and b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-Millimeter-scale-1-Google-Chrome-linux.png differ diff --git a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-circle-should-look-right-1-Google-Chrome-linux.png b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-circle-should-look-right-1-Google-Chrome-linux.png index dbe9a64f7..d255cc56c 100644 Binary files a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-circle-should-look-right-1-Google-Chrome-linux.png and b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-circle-should-look-right-1-Google-Chrome-linux.png differ diff --git a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-rectangles-should-look-right-1-Google-Chrome-linux.png b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-rectangles-should-look-right-1-Google-Chrome-linux.png index 2b46c5fd3..5803cfb24 100644 Binary files a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-rectangles-should-look-right-1-Google-Chrome-linux.png and b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-rectangles-should-look-right-1-Google-Chrome-linux.png differ diff --git a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-1-Google-Chrome-linux.png b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-1-Google-Chrome-linux.png index e52a88d0c..bec87c282 100644 Binary files a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-1-Google-Chrome-linux.png and b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-1-Google-Chrome-linux.png differ diff --git a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-2-Google-Chrome-linux.png b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-2-Google-Chrome-linux.png index f77650e49..f67c094a5 100644 Binary files a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-2-Google-Chrome-linux.png and b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-2-Google-Chrome-linux.png differ diff --git a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Sketch-on-face-with-none-z-up-1-Google-Chrome-linux.png b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Sketch-on-face-with-none-z-up-1-Google-Chrome-linux.png index 1be9a0943..af51a0fa3 100644 Binary files a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Sketch-on-face-with-none-z-up-1-Google-Chrome-linux.png and b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Sketch-on-face-with-none-z-up-1-Google-Chrome-linux.png differ diff --git a/e2e/playwright/testing-gizmo.spec.ts b/e2e/playwright/testing-gizmo.spec.ts index 49f06a84b..67e38a0ea 100644 --- a/e2e/playwright/testing-gizmo.spec.ts +++ b/e2e/playwright/testing-gizmo.spec.ts @@ -243,7 +243,7 @@ test.describe('Testing Gizmo', { tag: ['@skipWin'] }, () => { }) test.describe(`Testing gizmo, fixture-based`, () => { - test('Center on selection from menu', async ({ + test('Center on selection from menu, disable interaction in sketch mode', async ({ context, page, homePage, @@ -318,5 +318,26 @@ test.describe(`Testing gizmo, fixture-based`, () => { }, }) }) + + await test.step(`Gizmo should be disabled when in sketch mode`, async () => { + const sketchModeButton = page.getByRole('button', { + name: 'Edit sketch', + }) + const exitSketchButton = page.getByRole('button', { + name: 'Exit sketch', + }) + + await sketchModeButton.click() + await expect(exitSketchButton).toBeVisible() + const gizmoPopoverButton = page.getByRole('button', { + name: 'view settings', + }) + await gizmoPopoverButton.click() + const buttonToTest = page.getByRole('button', { + name: 'right view', + }) + await expect(buttonToTest).toBeVisible() + await expect(buttonToTest).toBeDisabled() + }) }) }) diff --git a/src/components/Gizmo.tsx b/src/components/Gizmo.tsx index c30139c67..b500b1332 100644 --- a/src/components/Gizmo.tsx +++ b/src/components/Gizmo.tsx @@ -27,6 +27,8 @@ import { ViewControlContextMenu, } from './ViewControlMenu' import { AxisNames } from 'lib/constants' +import { useModelingContext } from 'hooks/useModelingContext' +import { useSettings } from 'machines/appMachine' const CANVAS_SIZE = 80 const FRUSTUM_SIZE = 0.5 @@ -40,12 +42,33 @@ enum AxisColors { } export default function Gizmo() { + const { state: modelingState } = useModelingContext() + const settings = useSettings() const menuItems = useViewControlMenuItems() const wrapperRef = useRef(null) const canvasRef = useRef(null) const raycasterIntersect = useRef | null>(null) const cameraPassiveUpdateTimer = useRef(0) const raycasterPassiveUpdateTimer = useRef(0) + const disableOrbitRef = useRef(false) + + // Temporary fix for #4040: + // Disable gizmo orbiting in sketch mode + // This effect updates disableOrbitRef whenever the user + // toggles between Sketch mode and 3D mode + useEffect(() => { + disableOrbitRef.current = + modelingState.matches('Sketch') && + !settings.app.allowOrbitInSketchMode.current + if (wrapperRef.current) { + wrapperRef.current.style.filter = disableOrbitRef.current + ? 'grayscale(100%)' + : 'none' + wrapperRef.current.style.cursor = disableOrbitRef.current + ? 'not-allowed' + : 'auto' + } + }, [modelingState, settings.app.allowOrbitInSketchMode.current]) useEffect(() => { if (!canvasRef.current) return @@ -64,7 +87,8 @@ export default function Gizmo() { const { mouse, disposeMouseEvents } = initializeMouseEvents( canvas, raycasterIntersect, - sceneInfra + sceneInfra, + disableOrbitRef ) const raycasterObjects = [...gizmoAxisHeads] @@ -81,15 +105,21 @@ export default function Gizmo() { delta, cameraPassiveUpdateTimer ) - updateRayCaster( - raycasterObjects, - raycaster, - mouse, - camera, - raycasterIntersect, - delta, - raycasterPassiveUpdateTimer - ) + // If orbits are disabled, skip click logic + if (!disableOrbitRef.current) { + updateRayCaster( + raycasterObjects, + raycaster, + mouse, + camera, + raycasterIntersect, + delta, + raycasterPassiveUpdateTimer + ) + } else { + raycasterObjects.forEach((object) => object.scale.set(1, 1, 1)) // Reset scales + raycasterIntersect.current = null // Clear intersection + } renderer.render(scene, camera) requestAnimationFrame(animate) } @@ -246,7 +276,8 @@ const quaternionsEqual = ( const initializeMouseEvents = ( canvas: HTMLCanvasElement, raycasterIntersect: MutableRefObject | null>, - sceneInfra: SceneInfra + sceneInfra: SceneInfra, + disableOrbitRef: MutableRefObject ): { mouse: Vector2; disposeMouseEvents: () => void } => { const mouse = new Vector2() mouse.x = 1 // fix initial mouse position issue @@ -258,10 +289,10 @@ const initializeMouseEvents = ( } const handleClick = () => { - if (raycasterIntersect.current) { - const axisName = raycasterIntersect.current.object.name as AxisNames - sceneInfra.camControls.updateCameraToAxis(axisName).catch(reportRejection) - } + // If orbits are disabled, skip click logic + if (disableOrbitRef.current || !raycasterIntersect.current) return + const axisName = raycasterIntersect.current.object.name as AxisNames + sceneInfra.camControls.updateCameraToAxis(axisName).catch(reportRejection) } window.addEventListener('mousemove', handleMouseMove) diff --git a/src/components/ViewControlMenu.tsx b/src/components/ViewControlMenu.tsx index 68c8b2578..4e9c8c5bd 100644 --- a/src/components/ViewControlMenu.tsx +++ b/src/components/ViewControlMenu.tsx @@ -10,9 +10,14 @@ import { AxisNames, VIEW_NAMES_SEMANTIC } from 'lib/constants' import { useModelingContext } from 'hooks/useModelingContext' import { useMemo } from 'react' import { sceneInfra } from 'lib/singletons' +import { useSettings } from 'machines/appMachine' export function useViewControlMenuItems() { - const { send: modelingSend } = useModelingContext() + const { state: modelingState, send: modelingSend } = useModelingContext() + const settings = useSettings() + const shouldLockView = + modelingState.matches('Sketch') && + !settings.app.allowOrbitInSketchMode.current const menuItems = useMemo( () => [ ...Object.entries(VIEW_NAMES_SEMANTIC).map(([axisName, axisSemantic]) => ( @@ -23,6 +28,7 @@ export function useViewControlMenuItems() { .updateCameraToAxis(axisName as AxisNames) .catch(reportRejection) }} + disabled={shouldLockView} > {axisSemantic} view @@ -32,6 +38,7 @@ export function useViewControlMenuItems() { onClick={() => { sceneInfra.camControls.resetCameraPosition().catch(reportRejection) }} + disabled={shouldLockView} > Reset view , @@ -39,13 +46,14 @@ export function useViewControlMenuItems() { onClick={() => { modelingSend({ type: 'Center camera on selection' }) }} + disabled={shouldLockView} > Center view on selection , , , ], - [VIEW_NAMES_SEMANTIC] + [VIEW_NAMES_SEMANTIC, shouldLockView] ) return menuItems }