add the ability to edit sketch later
This commit is contained in:
50
src/App.tsx
50
src/App.tsx
@ -3,7 +3,11 @@ import { Canvas } from '@react-three/fiber'
|
|||||||
import { Allotment } from 'allotment'
|
import { Allotment } from 'allotment'
|
||||||
import { OrbitControls, OrthographicCamera } from '@react-three/drei'
|
import { OrbitControls, OrthographicCamera } from '@react-three/drei'
|
||||||
import { lexer } from './lang/tokeniser'
|
import { lexer } from './lang/tokeniser'
|
||||||
import { abstractSyntaxTree } from './lang/abstractSyntaxTree'
|
import {
|
||||||
|
abstractSyntaxTree,
|
||||||
|
getNodePathFromSourceRange,
|
||||||
|
getNodeFromPath
|
||||||
|
} from './lang/abstractSyntaxTree'
|
||||||
import { executor, processShownObjects, ViewerArtifact } from './lang/executor'
|
import { executor, processShownObjects, ViewerArtifact } from './lang/executor'
|
||||||
import { recast } from './lang/recast'
|
import { recast } from './lang/recast'
|
||||||
import { BufferGeometry } from 'three'
|
import { BufferGeometry } from 'three'
|
||||||
@ -32,7 +36,6 @@ function App() {
|
|||||||
setSelectionRange,
|
setSelectionRange,
|
||||||
selectionRange,
|
selectionRange,
|
||||||
guiMode,
|
guiMode,
|
||||||
setGuiMode,
|
|
||||||
lastGuiMode,
|
lastGuiMode,
|
||||||
removeError,
|
removeError,
|
||||||
addLog,
|
addLog,
|
||||||
@ -41,6 +44,8 @@ function App() {
|
|||||||
setAst,
|
setAst,
|
||||||
formatCode,
|
formatCode,
|
||||||
ast,
|
ast,
|
||||||
|
setError,
|
||||||
|
errorState,
|
||||||
} = useStore((s) => ({
|
} = useStore((s) => ({
|
||||||
editorView: s.editorView,
|
editorView: s.editorView,
|
||||||
setEditorView: s.setEditorView,
|
setEditorView: s.setEditorView,
|
||||||
@ -56,6 +61,8 @@ function App() {
|
|||||||
setAst: s.setAst,
|
setAst: s.setAst,
|
||||||
lastGuiMode: s.lastGuiMode,
|
lastGuiMode: s.lastGuiMode,
|
||||||
formatCode: s.formatCode,
|
formatCode: s.formatCode,
|
||||||
|
setError: s.setError,
|
||||||
|
errorState: s.errorState,
|
||||||
}))
|
}))
|
||||||
// const onChange = React.useCallback((value: string, viewUpdate: ViewUpdate) => {
|
// const onChange = React.useCallback((value: string, viewUpdate: ViewUpdate) => {
|
||||||
const onChange = (value: string, viewUpdate: ViewUpdate) => {
|
const onChange = (value: string, viewUpdate: ViewUpdate) => {
|
||||||
@ -110,8 +117,9 @@ function App() {
|
|||||||
setGeoArray(geos)
|
setGeoArray(geos)
|
||||||
removeError()
|
removeError()
|
||||||
console.log(programMemory)
|
console.log(programMemory)
|
||||||
|
setError()
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
setGuiMode({ mode: 'codeError' })
|
setError('problem')
|
||||||
console.log(e)
|
console.log(e)
|
||||||
addLog(e)
|
addLog(e)
|
||||||
}
|
}
|
||||||
@ -173,7 +181,7 @@ function App() {
|
|||||||
<AxisIndicator />
|
<AxisIndicator />
|
||||||
</Canvas>
|
</Canvas>
|
||||||
</div>
|
</div>
|
||||||
{guiMode.mode === 'codeError' && (
|
{errorState.isError && (
|
||||||
<div className="absolute inset-0 bg-gray-700/20">
|
<div className="absolute inset-0 bg-gray-700/20">
|
||||||
<pre>
|
<pre>
|
||||||
{'last first: \n\n' +
|
{'last first: \n\n' +
|
||||||
@ -201,19 +209,39 @@ function Line({
|
|||||||
sourceRange: [number, number]
|
sourceRange: [number, number]
|
||||||
forceHighlight?: boolean
|
forceHighlight?: boolean
|
||||||
}) {
|
}) {
|
||||||
const { setHighlightRange, selectionRange } = useStore(
|
const { setHighlightRange, selectionRange, guiMode, setGuiMode, ast } =
|
||||||
({ setHighlightRange, selectionRange }) => ({
|
useStore(
|
||||||
setHighlightRange,
|
({ setHighlightRange, selectionRange, guiMode, setGuiMode, ast }) => ({
|
||||||
selectionRange,
|
setHighlightRange,
|
||||||
})
|
selectionRange,
|
||||||
)
|
guiMode,
|
||||||
|
setGuiMode,
|
||||||
|
ast,
|
||||||
|
})
|
||||||
|
)
|
||||||
// This reference will give us direct access to the mesh
|
// This reference will give us direct access to the mesh
|
||||||
const ref = useRef<BufferGeometry | undefined>() as any
|
const ref = useRef<BufferGeometry | undefined>() as any
|
||||||
const [hovered, setHover] = useState(false)
|
const [hovered, setHover] = useState(false)
|
||||||
const [editorCursor, setEditorCursor] = useState(false)
|
const [editorCursor, setEditorCursor] = useState(false)
|
||||||
|
const [didSetCanEdit, setDidSetCanEdit] = useState(false)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const shouldHighlight = isOverlapping(sourceRange, selectionRange)
|
const shouldHighlight = isOverlapping(sourceRange, selectionRange)
|
||||||
setEditorCursor(shouldHighlight)
|
setEditorCursor(shouldHighlight)
|
||||||
|
if (shouldHighlight && guiMode.mode === 'default' && ast) {
|
||||||
|
const pathToNode = getNodePathFromSourceRange(ast, sourceRange)
|
||||||
|
const piper = getNodeFromPath(ast, pathToNode, 'PipeExpression')
|
||||||
|
const axis = piper.type !== 'PipeExpression' ? 'xy'
|
||||||
|
: piper?.body?.[1]?.callee?.name === 'rx' ? 'xz' : 'yz'
|
||||||
|
setGuiMode({ mode: 'canEditSketch', pathToNode, axis })
|
||||||
|
setDidSetCanEdit(true)
|
||||||
|
} else if (
|
||||||
|
!shouldHighlight &&
|
||||||
|
didSetCanEdit &&
|
||||||
|
guiMode.mode === 'canEditSketch'
|
||||||
|
) {
|
||||||
|
setGuiMode({ mode: 'default' })
|
||||||
|
setDidSetCanEdit(false)
|
||||||
|
}
|
||||||
}, [selectionRange, sourceRange])
|
}, [selectionRange, sourceRange])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -257,7 +285,7 @@ function RenderViewerArtifacts({
|
|||||||
const shouldHighlight = isOverlapping(artifact.sourceRange, selectionRange)
|
const shouldHighlight = isOverlapping(artifact.sourceRange, selectionRange)
|
||||||
setEditorCursor(shouldHighlight)
|
setEditorCursor(shouldHighlight)
|
||||||
}, [selectionRange, artifact.sourceRange])
|
}, [selectionRange, artifact.sourceRange])
|
||||||
if (artifact.type === 'geo') {
|
if (artifact.type === 'sketchLine') {
|
||||||
const { geo, sourceRange } = artifact
|
const { geo, sourceRange } = artifact
|
||||||
return (
|
return (
|
||||||
<Line
|
<Line
|
||||||
|
@ -15,16 +15,50 @@ export const Toolbar = () => {
|
|||||||
sketchMode: 'selectFace',
|
sketchMode: 'selectFace',
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
|
className="border m-1 px-1 rounded"
|
||||||
>
|
>
|
||||||
Start sketch
|
Start sketch
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
{guiMode.mode === 'sketch' && guiMode.sketchMode === 'points' && (
|
{guiMode.mode === 'canEditSketch' && (
|
||||||
<button>LineTo TODO</button>
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
setGuiMode({
|
||||||
|
mode: 'sketch',
|
||||||
|
sketchMode: 'sketchEdit',
|
||||||
|
pathToNode: guiMode.pathToNode,
|
||||||
|
axis: guiMode.axis,
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
className="border m-1 px-1 rounded"
|
||||||
|
>
|
||||||
|
EditSketch
|
||||||
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{guiMode.mode !== 'default' && (
|
{guiMode.mode !== 'default' && (
|
||||||
<button onClick={() => setGuiMode({ mode: 'default' })}>exit</button>
|
<button
|
||||||
|
onClick={() => setGuiMode({ mode: 'default' })}
|
||||||
|
className="border m-1 px-1 rounded"
|
||||||
|
>
|
||||||
|
Exit sketch
|
||||||
|
</button>
|
||||||
)}
|
)}
|
||||||
|
{guiMode.mode === 'sketch' &&
|
||||||
|
(guiMode.sketchMode === 'points' ||
|
||||||
|
guiMode.sketchMode === 'sketchEdit') && (
|
||||||
|
<button
|
||||||
|
className={`border m-1 px-1 rounded ${
|
||||||
|
guiMode.sketchMode === 'points' && 'bg-gray-400'
|
||||||
|
}`}
|
||||||
|
onClick={() => setGuiMode({
|
||||||
|
...guiMode,
|
||||||
|
sketchMode: guiMode.sketchMode === 'points' ? 'sketchEdit' :'points',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
LineTo{guiMode.sketchMode === 'points' && '✅'}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -56,9 +56,8 @@ export const BasePlanes = () => {
|
|||||||
|
|
||||||
setGuiMode({
|
setGuiMode({
|
||||||
mode: 'sketch',
|
mode: 'sketch',
|
||||||
sketchMode: 'points',
|
sketchMode: 'sketchEdit',
|
||||||
axis,
|
axis,
|
||||||
id,
|
|
||||||
pathToNode,
|
pathToNode,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ export const SketchPlane = () => {
|
|||||||
if (guiMode.mode !== 'sketch') {
|
if (guiMode.mode !== 'sketch') {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
if (guiMode.sketchMode !== 'points') {
|
if (guiMode.sketchMode !== 'points' && guiMode.sketchMode !== 'sketchEdit' ) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,6 +38,9 @@ export const SketchPlane = () => {
|
|||||||
rotation={clickDetectPlaneRotation}
|
rotation={clickDetectPlaneRotation}
|
||||||
name={sketchGridName}
|
name={sketchGridName}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
|
if (guiMode.sketchMode !== 'points') {
|
||||||
|
return
|
||||||
|
}
|
||||||
const sketchGridIntersection = e.intersections.find(
|
const sketchGridIntersection = e.intersections.find(
|
||||||
({ object }) => object.name === sketchGridName
|
({ object }) => object.name === sketchGridName
|
||||||
)
|
)
|
||||||
|
@ -1176,7 +1176,8 @@ export function addLine(
|
|||||||
const dumbyStartend = { start: 0, end: 0 }
|
const dumbyStartend = { start: 0, end: 0 }
|
||||||
const sketchExpression = getNodeFromPath(
|
const sketchExpression = getNodeFromPath(
|
||||||
_node,
|
_node,
|
||||||
pathToNode
|
pathToNode,
|
||||||
|
'SketchExpression'
|
||||||
) as SketchExpression
|
) as SketchExpression
|
||||||
const line: ExpressionStatement = {
|
const line: ExpressionStatement = {
|
||||||
type: 'ExpressionStatement',
|
type: 'ExpressionStatement',
|
||||||
@ -1263,8 +1264,13 @@ function debuggerr(tokens: Token[], indexes: number[], msg = ''): string {
|
|||||||
return debugResult
|
return debugResult
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getNodeFromPath(node: Program, path: (string | number)[]) {
|
export function getNodeFromPath(
|
||||||
|
node: Program,
|
||||||
|
path: (string | number)[],
|
||||||
|
stopAt: string = ''
|
||||||
|
) {
|
||||||
let currentNode = node as any
|
let currentNode = node as any
|
||||||
|
let stopAtNode = null
|
||||||
let successfulPaths: (string | number)[] = []
|
let successfulPaths: (string | number)[] = []
|
||||||
for (const pathItem of path) {
|
for (const pathItem of path) {
|
||||||
try {
|
try {
|
||||||
@ -1272,6 +1278,11 @@ export function getNodeFromPath(node: Program, path: (string | number)[]) {
|
|||||||
throw new Error('not an object')
|
throw new Error('not an object')
|
||||||
currentNode = currentNode[pathItem]
|
currentNode = currentNode[pathItem]
|
||||||
successfulPaths.push(pathItem)
|
successfulPaths.push(pathItem)
|
||||||
|
if (currentNode.type === stopAt) {
|
||||||
|
// it will match the deepest node of the type
|
||||||
|
// instead of returning at the first match
|
||||||
|
stopAtNode = currentNode
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Could not find path ${pathItem} in node ${JSON.stringify(
|
`Could not find path ${pathItem} in node ${JSON.stringify(
|
||||||
@ -1282,7 +1293,7 @@ export function getNodeFromPath(node: Program, path: (string | number)[]) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return currentNode
|
return stopAtNode || currentNode
|
||||||
}
|
}
|
||||||
|
|
||||||
type Path = (string | number)[]
|
type Path = (string | number)[]
|
||||||
|
@ -3,7 +3,7 @@ import fs from 'node:fs'
|
|||||||
import { abstractSyntaxTree } from './abstractSyntaxTree'
|
import { abstractSyntaxTree } from './abstractSyntaxTree'
|
||||||
import { lexer } from './tokeniser'
|
import { lexer } from './tokeniser'
|
||||||
import { executor, ProgramMemory } from './executor'
|
import { executor, ProgramMemory } from './executor'
|
||||||
import { Transform } from './sketch'
|
import { Transform, SketchGeo } from './sketch'
|
||||||
|
|
||||||
describe('test', () => {
|
describe('test', () => {
|
||||||
it('test assigning two variables, the second summing with the first', () => {
|
it('test assigning two variables, the second summing with the first', () => {
|
||||||
@ -64,7 +64,7 @@ show(mySketch)
|
|||||||
`
|
`
|
||||||
const { root, return: _return } = exe(code)
|
const { root, return: _return } = exe(code)
|
||||||
expect(
|
expect(
|
||||||
root.mySketch.map(
|
root.mySketch.sketch.map(
|
||||||
({ previousPath, firstPath, geo, ...rest }: any) => rest
|
({ previousPath, firstPath, geo, ...rest }: any) => rest
|
||||||
)
|
)
|
||||||
).toEqual([
|
).toEqual([
|
||||||
@ -77,7 +77,7 @@ show(mySketch)
|
|||||||
sourceRange: [93, 100],
|
sourceRange: [93, 100],
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
expect(root.mySketch[0]).toEqual(root.mySketch[4].firstPath)
|
expect(root.mySketch.sketch[0]).toEqual(root.mySketch.sketch[4].firstPath)
|
||||||
// hmm not sure what handle the "show" function
|
// hmm not sure what handle the "show" function
|
||||||
expect(_return).toEqual([
|
expect(_return).toEqual([
|
||||||
{
|
{
|
||||||
@ -109,7 +109,7 @@ show(mySketch)
|
|||||||
// 'show(mySk1)',
|
// 'show(mySk1)',
|
||||||
].join('\n')
|
].join('\n')
|
||||||
const { root } = exe(code)
|
const { root } = exe(code)
|
||||||
expect(root.mySk1).toHaveLength(4)
|
expect(root.mySk1.sketch).toHaveLength(4)
|
||||||
expect(root?.rotated?.type).toBe('transform')
|
expect(root?.rotated?.type).toBe('transform')
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -124,9 +124,7 @@ show(mySketch)
|
|||||||
const { root } = exe(code)
|
const { root } = exe(code)
|
||||||
const striptVersion = removeGeoFromSketch(root.mySk1)
|
const striptVersion = removeGeoFromSketch(root.mySk1)
|
||||||
expect(striptVersion).toEqual({
|
expect(striptVersion).toEqual({
|
||||||
type: 'transform',
|
type: 'sketchGeo',
|
||||||
rotation: [1.5707963267948966, 0, 0],
|
|
||||||
transform: [0, 0, 0],
|
|
||||||
sketch: [
|
sketch: [
|
||||||
{
|
{
|
||||||
type: 'base',
|
type: 'base',
|
||||||
@ -150,8 +148,38 @@ show(mySketch)
|
|||||||
sourceRange: [60, 71],
|
sourceRange: [60, 71],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
sourceRange: [77, 86],
|
sourceRange: [13, 73],
|
||||||
})
|
})
|
||||||
|
// old expect
|
||||||
|
// expect(striptVersion).toEqual({
|
||||||
|
// type: 'transform',
|
||||||
|
// rotation: [1.5707963267948966, 0, 0],
|
||||||
|
// transform: [0, 0, 0],
|
||||||
|
// sketch: [
|
||||||
|
// {
|
||||||
|
// type: 'base',
|
||||||
|
// from: [0, 0],
|
||||||
|
// sourceRange: [0, 0],
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// type: 'toPoint',
|
||||||
|
// to: [1, 1],
|
||||||
|
// sourceRange: [17, 28],
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// type: 'toPoint',
|
||||||
|
// to: [0, 1],
|
||||||
|
// sourceRange: [36, 57],
|
||||||
|
// name: 'myPath',
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// type: 'toPoint',
|
||||||
|
// to: [1, 1],
|
||||||
|
// sourceRange: [60, 71],
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// sourceRange: [77, 86],
|
||||||
|
// })
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -166,8 +194,8 @@ function exe(
|
|||||||
return executor(ast, programMemory)
|
return executor(ast, programMemory)
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeGeoFromSketch(sketch: Transform): any {
|
function removeGeoFromSketch(sketch: Transform | SketchGeo): any {
|
||||||
if (!Array.isArray(sketch.sketch)) {
|
if (sketch.type !== 'sketchGeo') {
|
||||||
return removeGeoFromSketch(sketch.sketch)
|
return removeGeoFromSketch(sketch.sketch)
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
@ -4,7 +4,7 @@ import {
|
|||||||
BinaryExpression,
|
BinaryExpression,
|
||||||
PipeExpression,
|
PipeExpression,
|
||||||
} from './abstractSyntaxTree'
|
} from './abstractSyntaxTree'
|
||||||
import { Path, Transform, sketchFns } from './sketch'
|
import { Path, Transform, SketchGeo, sketchFns } from './sketch'
|
||||||
import { BufferGeometry } from 'three'
|
import { BufferGeometry } from 'three'
|
||||||
|
|
||||||
export interface ProgramMemory {
|
export interface ProgramMemory {
|
||||||
@ -63,7 +63,12 @@ export const executor = (
|
|||||||
)
|
)
|
||||||
_sketch = newProgramMemory._sketch
|
_sketch = newProgramMemory._sketch
|
||||||
}
|
}
|
||||||
_programMemory.root[variableName] = _sketch
|
const newSketch: SketchGeo = {
|
||||||
|
type: 'sketchGeo',
|
||||||
|
sketch: _sketch,
|
||||||
|
sourceRange: [sketchInit.start, sketchInit.end],
|
||||||
|
}
|
||||||
|
_programMemory.root[variableName] = newSketch
|
||||||
} else if (declaration.init.type === 'FunctionExpression') {
|
} else if (declaration.init.type === 'FunctionExpression') {
|
||||||
const fnInit = declaration.init
|
const fnInit = declaration.init
|
||||||
|
|
||||||
@ -271,9 +276,14 @@ function executePipeBody(
|
|||||||
_sketch = newProgramMemory._sketch
|
_sketch = newProgramMemory._sketch
|
||||||
}
|
}
|
||||||
// _programMemory.root[variableName] = _sketch
|
// _programMemory.root[variableName] = _sketch
|
||||||
|
const newSketch: SketchGeo = {
|
||||||
|
type: 'sketchGeo',
|
||||||
|
sketch: _sketch,
|
||||||
|
sourceRange: [expression.start, expression.end],
|
||||||
|
}
|
||||||
return executePipeBody(body, programMemory, expressionIndex + 1, [
|
return executePipeBody(body, programMemory, expressionIndex + 1, [
|
||||||
...previousResults,
|
...previousResults,
|
||||||
_sketch,
|
newSketch,
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,7 +294,7 @@ type SourceRange = [number, number]
|
|||||||
|
|
||||||
export type ViewerArtifact =
|
export type ViewerArtifact =
|
||||||
| {
|
| {
|
||||||
type: 'geo'
|
type: 'sketchLine'
|
||||||
sourceRange: SourceRange
|
sourceRange: SourceRange
|
||||||
geo: BufferGeometry
|
geo: BufferGeometry
|
||||||
}
|
}
|
||||||
@ -301,11 +311,11 @@ type PreviousTransforms = {
|
|||||||
|
|
||||||
export const processShownObjects = (
|
export const processShownObjects = (
|
||||||
programMemory: ProgramMemory,
|
programMemory: ProgramMemory,
|
||||||
geoMeta: Path[] | Transform,
|
geoMeta: SketchGeo | Transform,
|
||||||
previousTransforms: PreviousTransforms = []
|
previousTransforms: PreviousTransforms = []
|
||||||
): ViewerArtifact[] => {
|
): ViewerArtifact[] => {
|
||||||
if (Array.isArray(geoMeta)) {
|
if (geoMeta?.type === 'sketchGeo') {
|
||||||
return geoMeta.map(({ geo, sourceRange }) => {
|
return geoMeta.sketch.map(({ geo, sourceRange }) => {
|
||||||
const newGeo = geo.clone()
|
const newGeo = geo.clone()
|
||||||
previousTransforms.forEach(({ rotation, transform }) => {
|
previousTransforms.forEach(({ rotation, transform }) => {
|
||||||
newGeo.rotateX(rotation[0])
|
newGeo.rotateX(rotation[0])
|
||||||
@ -315,7 +325,7 @@ export const processShownObjects = (
|
|||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: 'geo',
|
type: 'sketchLine',
|
||||||
geo: newGeo,
|
geo: newGeo,
|
||||||
sourceRange,
|
sourceRange,
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,13 @@ export interface Transform {
|
|||||||
type: 'transform'
|
type: 'transform'
|
||||||
rotation: Rotation3
|
rotation: Rotation3
|
||||||
transform: Translate3
|
transform: Translate3
|
||||||
sketch: Path[] | Transform
|
sketch: SketchGeo | Transform
|
||||||
|
sourceRange: SourceRange
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SketchGeo {
|
||||||
|
type: 'sketchGeo'
|
||||||
|
sketch: Path[]
|
||||||
sourceRange: SourceRange
|
sourceRange: SourceRange
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,7 +219,7 @@ function RotateOnAxis(axisMultiplier: [number, number, number]) {
|
|||||||
programMemory: ProgramMemory,
|
programMemory: ProgramMemory,
|
||||||
sourceRange: SourceRange,
|
sourceRange: SourceRange,
|
||||||
rotationD: number,
|
rotationD: number,
|
||||||
sketch: Path[] | Transform
|
sketch: SketchGeo | Transform
|
||||||
): Transform => {
|
): Transform => {
|
||||||
const rotationR = rotationD * (Math.PI / 180)
|
const rotationR = rotationD * (Math.PI / 180)
|
||||||
return {
|
return {
|
||||||
|
@ -6,6 +6,9 @@ import { lexer } from './lang/tokeniser'
|
|||||||
|
|
||||||
export type Range = [number, number]
|
export type Range = [number, number]
|
||||||
|
|
||||||
|
type Plane = 'xy' | 'xz' | 'yz'
|
||||||
|
type PathToNode = (string | number)[]
|
||||||
|
|
||||||
type GuiModes =
|
type GuiModes =
|
||||||
| {
|
| {
|
||||||
mode: 'default'
|
mode: 'default'
|
||||||
@ -13,17 +16,25 @@ type GuiModes =
|
|||||||
| {
|
| {
|
||||||
mode: 'sketch'
|
mode: 'sketch'
|
||||||
sketchMode: 'points'
|
sketchMode: 'points'
|
||||||
axis: 'xy' | 'xz' | 'yz'
|
axis: Plane
|
||||||
id?: string
|
id?: string
|
||||||
pathToNode: (string | number)[]
|
pathToNode: PathToNode
|
||||||
}
|
}
|
||||||
|
| {
|
||||||
|
mode: 'sketch'
|
||||||
|
sketchMode: 'sketchEdit'
|
||||||
|
axis: Plane
|
||||||
|
pathToNode: PathToNode
|
||||||
|
}
|
||||||
| {
|
| {
|
||||||
mode: 'sketch'
|
mode: 'sketch'
|
||||||
sketchMode: 'selectFace'
|
sketchMode: 'selectFace'
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
mode: 'codeError'
|
mode: 'canEditSketch'
|
||||||
}
|
pathToNode: PathToNode
|
||||||
|
axis: Plane
|
||||||
|
}
|
||||||
|
|
||||||
interface StoreState {
|
interface StoreState {
|
||||||
editorView: EditorView | null
|
editorView: EditorView | null
|
||||||
@ -45,6 +56,11 @@ interface StoreState {
|
|||||||
code: string
|
code: string
|
||||||
setCode: (code: string) => void
|
setCode: (code: string) => void
|
||||||
formatCode: () => void
|
formatCode: () => void
|
||||||
|
errorState: {
|
||||||
|
isError: boolean
|
||||||
|
error: string
|
||||||
|
}
|
||||||
|
setError: (error?: string) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useStore = create<StoreState>()((set, get) => ({
|
export const useStore = create<StoreState>()((set, get) => ({
|
||||||
@ -69,19 +85,10 @@ export const useStore = create<StoreState>()((set, get) => ({
|
|||||||
setGuiMode: (guiMode) => {
|
setGuiMode: (guiMode) => {
|
||||||
const lastGuiMode = get().guiMode
|
const lastGuiMode = get().guiMode
|
||||||
set({ guiMode })
|
set({ guiMode })
|
||||||
if (guiMode.mode !== 'codeError') {
|
|
||||||
// don't set lastGuiMode to and error state
|
|
||||||
// as the point fo lastGuiMode is to restore the last healthy state
|
|
||||||
// todo maybe rename to lastHealthyGuiMode and remove this comment
|
|
||||||
set({ lastGuiMode })
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
removeError: () => {
|
removeError: () => {
|
||||||
const lastGuiMode = get().lastGuiMode
|
const lastGuiMode = get().lastGuiMode
|
||||||
const currentGuiMode = get().guiMode
|
const currentGuiMode = get().guiMode
|
||||||
if (currentGuiMode.mode === 'codeError') {
|
|
||||||
set({ guiMode: lastGuiMode })
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
logs: [],
|
logs: [],
|
||||||
addLog: (log) => {
|
addLog: (log) => {
|
||||||
@ -108,4 +115,11 @@ export const useStore = create<StoreState>()((set, get) => ({
|
|||||||
const newCode = recast(ast)
|
const newCode = recast(ast)
|
||||||
set({ code: newCode, ast })
|
set({ code: newCode, ast })
|
||||||
},
|
},
|
||||||
|
errorState: {
|
||||||
|
isError: false,
|
||||||
|
error: '',
|
||||||
|
},
|
||||||
|
setError: (error = '') => {
|
||||||
|
set({ errorState: { isError: !!error, error } })
|
||||||
|
}
|
||||||
}))
|
}))
|
||||||
|
Reference in New Issue
Block a user