* Split ModelingSidebar out into own component * Consolidate all ModelingPane components and config * Make ModelingSidebar a directory of components and config * Remove unused components * Proper pane styling * Make tooltip configurable to visually appear on hover only * Remove debug panel from App * Fix current tests * Rename to more intuitive names * Fix useEffect loop bug with showDebugPanel * Fix snapshot tests * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Rerun CI * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Merge branch 'main' into franknoirot/sidebar * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Rerun CI * Maybe some flakiness in the validation initScripts? * Avoid test flakiness by waiting for more signals that loading is completed * Don't assert, just wait for the element to be enabled * Don't let users accidentally click the gap between the pane and the side of the window * Firm up extrude from command bar test * Get rid of unused imports * Add setting to disable blinking cursor (#2065) * Add support for "current" marker in command bar for boolean settings * Add a cursorBlinking setting * Rename setting to blinkingCursor, honor it in the UI * Fix scroll layout bug in settings modal * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Rerun CI * CSS tweaks * Allow settings hotkey within KclEditorPane * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * Rerun CI * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Rerun CI * Ensure the KCL code panel is closed for camera movement test * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Make sure that the camera position inputs are ready to be read from * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Remove repeat awaits * Make camera position fields in debug pane update when the pane is initialized * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Undo that CameraControls change because it made other things weird * retry fixing camera move test * Fix race condition where cam setting cam position parts were overwriting each other * Rerun CI * Rerun CI --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
278 lines
8.0 KiB
TypeScript
278 lines
8.0 KiB
TypeScript
import { useRef, useEffect, useState } from 'react'
|
|
import { useModelingContext } from 'hooks/useModelingContext'
|
|
|
|
import { cameraMouseDragGuards } from 'lib/cameraControls'
|
|
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
|
import { useStore } from 'useStore'
|
|
import { ARROWHEAD, DEBUG_SHOW_BOTH_SCENES } from './sceneInfra'
|
|
import { ReactCameraProperties } from './CameraControls'
|
|
import { throttle } from 'lib/utils'
|
|
import { sceneInfra } from 'lib/singletons'
|
|
import {
|
|
EXTRA_SEGMENT_HANDLE,
|
|
PROFILE_START,
|
|
getParentGroup,
|
|
} from './sceneEntities'
|
|
|
|
function useShouldHideScene(): { hideClient: boolean; hideServer: boolean } {
|
|
const [isCamMoving, setIsCamMoving] = useState(false)
|
|
const [isTween, setIsTween] = useState(false)
|
|
|
|
const { state } = useModelingContext()
|
|
|
|
useEffect(() => {
|
|
sceneInfra.camControls.setIsCamMovingCallback((isMoving, isTween) => {
|
|
setIsCamMoving(isMoving)
|
|
setIsTween(isTween)
|
|
})
|
|
}, [])
|
|
|
|
if (DEBUG_SHOW_BOTH_SCENES || !isCamMoving)
|
|
return { hideClient: false, hideServer: false }
|
|
let hideServer = state.matches('Sketch')
|
|
if (isTween) {
|
|
hideServer = false
|
|
}
|
|
|
|
return { hideClient: !hideServer, hideServer }
|
|
}
|
|
|
|
export const ClientSideScene = ({
|
|
cameraControls,
|
|
}: {
|
|
cameraControls: ReturnType<
|
|
typeof useSettingsAuthContext
|
|
>['settings']['context']['modeling']['mouseControls']['current']
|
|
}) => {
|
|
const canvasRef = useRef<HTMLDivElement>(null)
|
|
const { state, send, context } = useModelingContext()
|
|
const { hideClient, hideServer } = useShouldHideScene()
|
|
const { setHighlightRange } = useStore((s) => ({
|
|
setHighlightRange: s.setHighlightRange,
|
|
highlightRange: s.highlightRange,
|
|
}))
|
|
|
|
// Listen for changes to the camera controls setting
|
|
// and update the client-side scene's controls accordingly.
|
|
useEffect(() => {
|
|
sceneInfra.camControls.interactionGuards =
|
|
cameraMouseDragGuards[cameraControls]
|
|
}, [cameraControls])
|
|
useEffect(() => {
|
|
sceneInfra.updateOtherSelectionColors(
|
|
state?.context?.selectionRanges?.otherSelections || []
|
|
)
|
|
}, [state?.context?.selectionRanges?.otherSelections])
|
|
|
|
useEffect(() => {
|
|
if (!canvasRef.current) return
|
|
const canvas = canvasRef.current
|
|
canvas.appendChild(sceneInfra.renderer.domElement)
|
|
sceneInfra.animate()
|
|
sceneInfra.setHighlightCallback(setHighlightRange)
|
|
canvas.addEventListener('mousemove', sceneInfra.onMouseMove, false)
|
|
canvas.addEventListener('mousedown', sceneInfra.onMouseDown, false)
|
|
canvas.addEventListener('mouseup', sceneInfra.onMouseUp, false)
|
|
sceneInfra.setSend(send)
|
|
return () => {
|
|
canvas?.removeEventListener('mousemove', sceneInfra.onMouseMove)
|
|
canvas?.removeEventListener('mousedown', sceneInfra.onMouseDown)
|
|
canvas?.removeEventListener('mouseup', sceneInfra.onMouseUp)
|
|
}
|
|
}, [])
|
|
|
|
let cursor = 'default'
|
|
if (state.matches('Sketch')) {
|
|
if (
|
|
context.mouseState.type === 'isHovering' &&
|
|
getParentGroup(context.mouseState.on, [
|
|
ARROWHEAD,
|
|
EXTRA_SEGMENT_HANDLE,
|
|
PROFILE_START,
|
|
])
|
|
) {
|
|
cursor = 'move'
|
|
} else if (context.mouseState.type === 'isDragging') {
|
|
cursor = 'grabbing'
|
|
} else if (
|
|
state.matches('Sketch.Line tool') ||
|
|
state.matches('Sketch.Tangential arc to')
|
|
) {
|
|
cursor = 'crosshair'
|
|
} else {
|
|
cursor = 'default'
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div
|
|
ref={canvasRef}
|
|
style={{ cursor: cursor }}
|
|
className={`absolute inset-0 h-full w-full transition-all duration-300 ${
|
|
hideClient ? 'opacity-0' : 'opacity-100'
|
|
} ${hideServer ? 'bg-black' : ''} ${
|
|
!hideClient && !hideServer && state.matches('Sketch')
|
|
? 'bg-black/80'
|
|
: ''
|
|
}`}
|
|
></div>
|
|
)
|
|
}
|
|
|
|
const throttled = throttle((a: ReactCameraProperties) => {
|
|
if (a.type === 'perspective' && a.fov) {
|
|
sceneInfra.camControls.dollyZoom(a.fov)
|
|
}
|
|
}, 1000 / 15)
|
|
|
|
export const CamDebugSettings = () => {
|
|
const [camSettings, setCamSettings] = useState<ReactCameraProperties>(
|
|
sceneInfra.camControls.reactCameraProperties
|
|
)
|
|
const [fov, setFov] = useState(12)
|
|
|
|
useEffect(() => {
|
|
sceneInfra.camControls.setReactCameraPropertiesCallback(setCamSettings)
|
|
}, [sceneInfra])
|
|
useEffect(() => {
|
|
if (camSettings.type === 'perspective' && camSettings.fov) {
|
|
setFov(camSettings.fov)
|
|
}
|
|
}, [(camSettings as any)?.fov])
|
|
|
|
return (
|
|
<div>
|
|
<h3>cam settings</h3>
|
|
perspective cam
|
|
<input
|
|
type="checkbox"
|
|
checked={camSettings.type === 'perspective'}
|
|
onChange={(e) => {
|
|
if (camSettings.type === 'perspective') {
|
|
sceneInfra.camControls.useOrthographicCamera()
|
|
} else {
|
|
sceneInfra.camControls.usePerspectiveCamera()
|
|
}
|
|
}}
|
|
/>
|
|
{camSettings.type === 'perspective' && (
|
|
<input
|
|
type="range"
|
|
min="4"
|
|
max="90"
|
|
step={0.5}
|
|
value={fov}
|
|
onChange={(e) => {
|
|
setFov(parseFloat(e.target.value))
|
|
|
|
throttled({
|
|
...camSettings,
|
|
fov: parseFloat(e.target.value),
|
|
})
|
|
}}
|
|
className="w-full cursor-pointer pointer-events-auto"
|
|
/>
|
|
)}
|
|
{camSettings.type === 'perspective' && (
|
|
<div>
|
|
<span>fov</span>
|
|
<input
|
|
type="number"
|
|
value={camSettings.fov}
|
|
className="text-black w-16"
|
|
onChange={(e) => {
|
|
sceneInfra.camControls.setCam({
|
|
...camSettings,
|
|
fov: parseFloat(e.target.value),
|
|
})
|
|
}}
|
|
/>
|
|
</div>
|
|
)}
|
|
{camSettings.type === 'orthographic' && (
|
|
<>
|
|
<div>
|
|
<span>fov</span>
|
|
<input
|
|
type="number"
|
|
value={camSettings.zoom}
|
|
className="text-black w-16"
|
|
onChange={(e) => {
|
|
sceneInfra.camControls.setCam({
|
|
...camSettings,
|
|
zoom: parseFloat(e.target.value),
|
|
})
|
|
}}
|
|
/>
|
|
</div>
|
|
</>
|
|
)}
|
|
<div>
|
|
Position
|
|
<ul className="flex">
|
|
<li>
|
|
<span className="pl-2 pr-1">x:</span>
|
|
<input
|
|
type="number"
|
|
step={5}
|
|
data-testid="cam-x-position"
|
|
value={camSettings.position[0]}
|
|
className="text-black w-16"
|
|
onChange={(e) => {
|
|
sceneInfra.camControls.setCam({
|
|
...camSettings,
|
|
position: [
|
|
parseFloat(e.target.value),
|
|
camSettings.position[1],
|
|
camSettings.position[2],
|
|
],
|
|
})
|
|
}}
|
|
/>
|
|
</li>
|
|
<li>
|
|
<span className="pl-2 pr-1">y:</span>
|
|
<input
|
|
type="number"
|
|
step={5}
|
|
data-testid="cam-y-position"
|
|
value={camSettings.position[1]}
|
|
className="text-black w-16"
|
|
onChange={(e) => {
|
|
sceneInfra.camControls.setCam({
|
|
...camSettings,
|
|
position: [
|
|
camSettings.position[0],
|
|
parseFloat(e.target.value),
|
|
camSettings.position[2],
|
|
],
|
|
})
|
|
}}
|
|
/>
|
|
</li>
|
|
<li>
|
|
<span className="pl-2 pr-1">z:</span>
|
|
<input
|
|
type="number"
|
|
step={5}
|
|
data-testid="cam-z-position"
|
|
value={camSettings.position[2]}
|
|
className="text-black w-16"
|
|
onChange={(e) => {
|
|
sceneInfra.camControls.setCam({
|
|
...camSettings,
|
|
position: [
|
|
camSettings.position[0],
|
|
camSettings.position[1],
|
|
parseFloat(e.target.value),
|
|
],
|
|
})
|
|
}}
|
|
/>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|