Files
modeling-app/src/App.tsx

267 lines
7.9 KiB
TypeScript
Raw Normal View History

import { useRef, useState, useEffect } from 'react'
2022-11-26 08:34:23 +11:00
import { Canvas } from '@react-three/fiber'
import { Allotment } from 'allotment'
import { OrbitControls, OrthographicCamera } from '@react-three/drei'
import { asyncLexer } from './lang/tokeniser'
import { abstractSyntaxTree } from './lang/abstractSyntaxTree'
import { executor, ExtrudeGroup, SketchGroup } from './lang/executor'
2022-11-26 08:34:23 +11:00
import CodeMirror from '@uiw/react-codemirror'
import { javascript } from '@codemirror/lang-javascript'
import { ViewUpdate } from '@codemirror/view'
import {
lineHighlightField,
addLineHighlight,
2022-11-26 08:34:23 +11:00
} from './editor/highlightextension'
import { useStore } from './useStore'
import { Toolbar } from './Toolbar'
import { BasePlanes } from './components/BasePlanes'
import { SketchPlane } from './components/SketchPlane'
import { Logs } from './components/Logs'
2022-11-28 21:05:56 +11:00
import { AxisIndicator } from './components/AxisIndicator'
2023-01-10 15:42:22 +11:00
import { RenderViewerArtifacts } from './components/RenderViewerArtifacts'
2023-02-02 20:41:28 +11:00
import { PanelHeader } from './components/PanelHeader'
2023-02-03 10:04:16 +11:00
import { MemoryPanel } from './components/MemoryPanel'
import { useHotKeyListener } from './hooks/useHotKeyListener'
import { Stream } from './components/Stream'
import ModalContainer from 'react-modal-promise'
2022-11-26 08:34:23 +11:00
const OrrthographicCamera = OrthographicCamera as any
2022-11-12 13:11:54 +11:00
function App() {
2022-11-26 08:34:23 +11:00
const cam = useRef()
useHotKeyListener()
const {
editorView,
setEditorView,
setSelectionRanges,
selectionRanges: selectionRange,
guiMode,
lastGuiMode,
addLog,
code,
setCode,
setAst,
2022-12-06 05:40:05 +11:00
setError,
errorState,
2023-01-04 01:28:26 +11:00
setProgramMemory,
resetLogs,
selectionRangeTypeMap,
} = useStore((s) => ({
editorView: s.editorView,
setEditorView: s.setEditorView,
setSelectionRanges: s.setSelectionRanges,
selectionRanges: s.selectionRanges,
guiMode: s.guiMode,
setGuiMode: s.setGuiMode,
addLog: s.addLog,
code: s.code,
setCode: s.setCode,
setAst: s.setAst,
2022-11-28 19:43:20 +11:00
lastGuiMode: s.lastGuiMode,
2022-12-06 05:40:05 +11:00
setError: s.setError,
errorState: s.errorState,
2023-01-04 01:28:26 +11:00
setProgramMemory: s.setProgramMemory,
resetLogs: s.resetLogs,
selectionRangeTypeMap: s.selectionRangeTypeMap,
}))
// const onChange = React.useCallback((value: string, viewUpdate: ViewUpdate) => {
const onChange = (value: string, viewUpdate: ViewUpdate) => {
2022-11-26 08:34:23 +11:00
setCode(value)
if (editorView) {
2022-11-26 08:34:23 +11:00
editorView?.dispatch({ effects: addLineHighlight.of([0, 0]) })
}
2022-11-26 08:34:23 +11:00
} //, []);
const onUpdate = (viewUpdate: ViewUpdate) => {
if (!editorView) {
2022-11-26 08:34:23 +11:00
setEditorView(viewUpdate.view)
}
const ranges = viewUpdate.state.selection.ranges
const isChange =
ranges.length !== selectionRange.codeBasedSelections.length ||
ranges.some(({ from, to }, i) => {
return (
from !== selectionRange.codeBasedSelections[i].range[0] ||
to !== selectionRange.codeBasedSelections[i].range[1]
)
})
if (!isChange) return
setSelectionRanges({
otherSelections: [],
codeBasedSelections: ranges.map(({ from, to }, i) => {
if (selectionRangeTypeMap[to]) {
return {
type: selectionRangeTypeMap[to],
range: [from, to],
}
}
return {
type: 'default',
range: [from, to],
}
}),
})
2022-11-26 08:34:23 +11:00
}
const [geoArray, setGeoArray] = useState<(ExtrudeGroup | SketchGroup)[]>([])
useEffect(() => {
const asyncWrap = async () => {
try {
if (!code) {
setGeoArray([])
setAst(null)
return
}
const tokens = await asyncLexer(code)
const _ast = abstractSyntaxTree(tokens)
setAst(_ast)
resetLogs()
const programMemory = executor(_ast, {
root: {
log: {
type: 'userVal',
value: (a: any) => {
addLog(a)
},
__meta: [
{
pathToNode: [],
sourceRange: [0, 0],
},
],
},
_0: {
type: 'userVal',
value: 0,
__meta: [],
},
_90: {
type: 'userVal',
value: 90,
__meta: [],
},
_180: {
type: 'userVal',
value: 180,
__meta: [],
},
_270: {
type: 'userVal',
value: 270,
__meta: [],
},
},
_sketch: [],
})
setProgramMemory(programMemory)
const geos = programMemory?.return
?.map(({ name }: { name: string }) => {
const artifact = programMemory?.root?.[name]
if (
artifact.type === 'extrudeGroup' ||
artifact.type === 'sketchGroup'
) {
return artifact
}
return null
})
.filter((a) => a) as (ExtrudeGroup | SketchGroup)[]
setGeoArray(geos)
console.log(programMemory)
setError()
} catch (e: any) {
setError('problem')
console.log(e)
addLog(e)
}
}
asyncWrap()
2022-11-26 08:34:23 +11:00
}, [code])
2022-11-12 13:11:54 +11:00
return (
<div className="h-screen">
<ModalContainer />
2023-02-02 20:41:28 +11:00
<Allotment snap={true}>
<Allotment vertical defaultSizes={[400, 1, 1]} minSize={20}>
2023-02-02 20:41:28 +11:00
<div className="h-full flex flex-col items-start">
2023-02-03 10:04:16 +11:00
<PanelHeader title="Editor" />
2023-02-02 20:41:28 +11:00
{/* <button
disabled={!shouldFormat}
onClick={formatCode}
className={`${!shouldFormat && 'text-gray-300'}`}
>
format
</button> */}
<div
className="bg-red h-full w-full overflow-auto"
id="code-mirror-override"
>
2023-02-02 20:41:28 +11:00
<CodeMirror
className="h-full"
value={code}
extensions={[javascript({ jsx: true }), lineHighlightField]}
onChange={onChange}
onUpdate={onUpdate}
onCreateEditor={(_editorView) => setEditorView(_editorView)}
/>
</div>
2022-11-28 19:43:20 +11:00
</div>
2023-02-03 10:04:16 +11:00
<MemoryPanel />
2023-02-02 20:41:28 +11:00
<Logs />
</Allotment>
<Allotment vertical defaultSizes={[1, 400]} minSize={20}>
<div className="h-full">
<PanelHeader title="Drafting Board" />
<Toolbar />
<div className="border h-full border-gray-300 relative">
<div className="absolute inset-0">
<Canvas>
<OrbitControls
enableDamping={false}
enablePan
enableRotate={
!(
guiMode.mode === 'canEditSketch' ||
guiMode.mode === 'sketch'
)
}
enableZoom
reverseOrbit={false}
/>
<OrrthographicCamera
ref={cam}
makeDefault
position={[0, 0, 1000]}
zoom={100}
rotation={[0, 0, 0]}
far={2000}
/>
<ambientLight />
<pointLight position={[10, 10, 10]} />
<RenderViewerArtifacts artifacts={geoArray} />
<BasePlanes />
<SketchPlane />
<AxisIndicator />
</Canvas>
2022-11-28 19:44:08 +11:00
</div>
{errorState.isError && (
<div className="absolute inset-0 bg-gray-700/20">
<pre>
{'last first: \n\n' +
JSON.stringify(lastGuiMode, null, 2) +
'\n\n' +
JSON.stringify(guiMode)}
</pre>
</div>
)}
</div>
</div>
<Stream />
</Allotment>
</Allotment>
2022-11-12 13:11:54 +11:00
</div>
2022-11-26 08:34:23 +11:00
)
2022-11-12 13:11:54 +11:00
}
2022-11-26 08:34:23 +11:00
export default App