diff --git a/online/src/app/classic/tools/strutdrag.jsx b/online/src/app/classic/tools/strutdrag.jsx index 2b3b79303..f283199ee 100644 --- a/online/src/app/classic/tools/strutdrag.jsx +++ b/online/src/app/classic/tools/strutdrag.jsx @@ -26,12 +26,15 @@ of TrackballControls.js and implement the transformations myself. See ObjectTra const StrutDragTool = props => { const eye = useThree(({ camera }) => camera.position); - const { startPreviewStrut, endPreviewStrut, movePreviewStrut } = useEditor(); + const { startPreviewStrut, endPreviewStrut, movePreviewStrut, scalePreviewStrut } = useEditor(); const [ line, setLine ] = createSignal( [ 0, 0, 1 ] ); const [ operating, setOperating ] = createSignal( null ); const [ position, setPosition ] = createSignal( [0,0,0] ); + let totalY = 0; + const MOUSE_WHEEL_TICKS_PER_SCALE = 25; + const handlers = { allowTrackball: false, @@ -42,9 +45,28 @@ const StrutDragTool = props => bkgdClick: () => {}, onDrag: evt => {}, + // untested, since UnifiedTool is in use + onWheel: deltaY => { + if ( operating() ) { + // Logic copied from the desktop implementation, so we are not so sensitive. + // (See LengthCanvasTool.java) + totalY += deltaY; + let increment = 0; + if ( totalY > MOUSE_WHEEL_TICKS_PER_SCALE ) + increment = +1; + else if ( totalY < -MOUSE_WHEEL_TICKS_PER_SCALE ) + increment = -1; + if ( increment ) { + scalePreviewStrut( -increment ); // sense must be reversed + totalY = 0; + } + } + }, + onDragStart: ( evt, id, position, type, selected ) => { if ( type !== 'ball' ) return; + totalY = 0; setPosition( position ); const { x, y, z } = new Vector3() .copy( eye() ) .sub( new Vector3( ...position ) ) .normalize(); setLine( [ x, y, z ] ); diff --git a/online/src/app/classic/tools/unified.jsx b/online/src/app/classic/tools/unified.jsx index 9efa2c0ab..c4a87df2f 100644 --- a/online/src/app/classic/tools/unified.jsx +++ b/online/src/app/classic/tools/unified.jsx @@ -7,7 +7,6 @@ import { useInteractionTool } from '../../../viewer/context/interaction.jsx'; import { ObjectTrackball } from './trackball.jsx'; import { VectorArrow } from './arrow.jsx'; import { subController, useEditor } from '../../framework/context/editor.jsx'; -import { useSymmetry } from "../context/symmetry.jsx"; /* This combines the behaviors of StrutDragTool and SelectionTool, to better @@ -19,7 +18,7 @@ I'd like to reuse their code, but that seems too complicated for the benefit. const UnifiedTool = props => { const eye = useThree(({ camera }) => camera.position); - const { startPreviewStrut, endPreviewStrut, movePreviewStrut, + const { startPreviewStrut, endPreviewStrut, movePreviewStrut, scalePreviewStrut, rootController, setState, controllerAction } = useEditor(); const pickingController = () => subController( rootController(), 'picking' ); @@ -27,6 +26,9 @@ const UnifiedTool = props => const [ operating, setOperating ] = createSignal( null ); const [ position, setPosition ] = createSignal( [0,0,0] ); + let totalY = 0; + const MOUSE_WHEEL_TICKS_PER_SCALE = 25; + const handlers = { allowTrackball: false, @@ -44,9 +46,27 @@ const UnifiedTool = props => controllerAction( rootController(), 'DeselectAll' ); }, + onWheel: deltaY => { + if ( operating() ) { + // Logic copied from the desktop implementation, so we are not so sensitive. + // (See LengthCanvasTool.java) + totalY += deltaY; + let increment = 0; + if ( totalY > MOUSE_WHEEL_TICKS_PER_SCALE ) + increment = +1; + else if ( totalY < -MOUSE_WHEEL_TICKS_PER_SCALE ) + increment = -1; + if ( increment ) { + scalePreviewStrut( -increment ); // sense must be reversed + totalY = 0; + } + } + }, + onDragStart: ( evt, id, position, type, selected ) => { if ( type !== 'ball' ) return; + totalY = 0; setPosition( position ); const { x, y, z } = new Vector3() .copy( eye() ) .sub( new Vector3( ...position ) ) .normalize(); setLine( [ x, y, z ] ); diff --git a/online/src/app/framework/context/editor.jsx b/online/src/app/framework/context/editor.jsx index a37e7a1c3..3e0a7d098 100644 --- a/online/src/app/framework/context/editor.jsx +++ b/online/src/app/framework/context/editor.jsx @@ -247,6 +247,7 @@ const EditorProvider = props => importMeshFile: ( file, format ) => workerClient .postMessage( actions.importMeshFile( file, format ) ), startPreviewStrut: ( id, dir ) => workerClient .postMessage( actions.startPreviewStrut( id, dir ) ), movePreviewStrut: ( direction ) => workerClient .postMessage( actions.movePreviewStrut( direction ) ), + scalePreviewStrut: ( increment ) => workerClient .postMessage( actions.scalePreviewStrut( increment ) ), endPreviewStrut: () => workerClient .postMessage( actions.endPreviewStrut() ), }; diff --git a/online/src/viewer/context/interaction.jsx b/online/src/viewer/context/interaction.jsx index a98a33622..c31483afe 100644 --- a/online/src/viewer/context/interaction.jsx +++ b/online/src/viewer/context/interaction.jsx @@ -37,6 +37,8 @@ const InteractionToolProvider = (props) => bkgdClick: () => tool() ?.bkgdClick(), + onWheel: dY => tool() ?.onWheel && tool() .onWheel( dY ), + onDragStart: ( e, id, position, type, selected ) => { // Defer the onDragStart until we see sufficient movement lastPointerDown = e; diff --git a/online/src/viewer/ltcanvas.jsx b/online/src/viewer/ltcanvas.jsx index bdd70e9ac..ec948d859 100644 --- a/online/src/viewer/ltcanvas.jsx +++ b/online/src/viewer/ltcanvas.jsx @@ -99,11 +99,19 @@ export const LightedTrackballCanvas = ( props ) => handler( e ); } } - const handlePointerMissed = ( e ) => + const handleWheel = ( e ) => + { + const handler = tool ?.onWheel; + if ( handler ) { + e.preventDefault(); + handler( e.deltaY ); + } + } + const handlePointerMissed = ( e ) => { const handler = tool ?.bkgdClick; if ( isLeftMouseButton( e ) && handler ) { - e.stopPropagation() + e.stopPropagation(); handler( e ); } } @@ -130,6 +138,7 @@ export const LightedTrackballCanvas = ( props ) => onMount( () => { // canvas .addEventListener( 'pointermove', handlePointerMove ); canvas .addEventListener( 'pointerup', handlePointerUp ); + canvas .addEventListener( 'wheel', handleWheel ); }); return canvas; diff --git a/online/src/viewer/util/actions.js b/online/src/viewer/util/actions.js index 08228109b..82ddb46a4 100644 --- a/online/src/viewer/util/actions.js +++ b/online/src/viewer/util/actions.js @@ -65,6 +65,8 @@ export const startPreviewStrut = ( ballId, direction ) => workerAction( 'PREVIEW export const movePreviewStrut = ( direction ) => workerAction( 'PREVIEW_STRUT_MOVE', { direction } ); +export const scalePreviewStrut = ( increment ) => workerAction( 'PREVIEW_STRUT_SCALE', { increment } ); + export const endPreviewStrut = () => workerAction( 'PREVIEW_STRUT_END', {} ); // This is for buildplane diff --git a/online/src/worker/legacy/controllers/index.js b/online/src/worker/legacy/controllers/index.js index bf84710df..9beaa8f18 100644 --- a/online/src/worker/legacy/controllers/index.js +++ b/online/src/worker/legacy/controllers/index.js @@ -49,6 +49,10 @@ const createControllers = ( design, renderingChanges, clientEvents ) => const [ x, y, z ] = direction; strutBuilder .previewStrut .zoneBall .setVector( new com.vzome.core.math.RealVector( x, y, z ) ); } + wrapper.scalePreviewStrut = increment => { + const lengthController = strutBuilder .previewStrut .getLengthController(); + lengthController .setScale( lengthController .getScale() + increment ); // will trigger side-effects + } wrapper.endPreviewStrut = () => { strutBuilder .previewStrut .finishPreview(); diff --git a/online/src/worker/vzome-worker-static.js b/online/src/worker/vzome-worker-static.js index 974025365..b60abdeb4 100644 --- a/online/src/worker/vzome-worker-static.js +++ b/online/src/worker/vzome-worker-static.js @@ -586,6 +586,13 @@ onmessage = ({ data }) => design.wrapper .movePreviewStrut( direction ); break; } + + case 'PREVIEW_STRUT_SCALE': + { + const { increment } = payload; + design.wrapper .scalePreviewStrut( increment ); + break; + } case 'PREVIEW_STRUT_END': {