Add modal typing back in, and clean up old constraints code (#865)
* Revert "Revert "Improve Prop Typings for Modals. Remove instances of `any`. (… (#813)"
This reverts commit 9822576077.
* tsc
* refactor all buttons
* add parallel constraint
* typegen?
* add constraint removal constraint
* add perpendicular distance constraint
* state diagram layout
* fmt
* improve modal typing for setAngleLength
			
			
This commit is contained in:
		@ -1,26 +1,13 @@
 | 
			
		||||
import { useStore, toolTips, ToolTip } from './useStore'
 | 
			
		||||
import { extrudeSketch, sketchOnExtrudedFace } from './lang/modifyAst'
 | 
			
		||||
import { getNodePathFromSourceRange } from './lang/queryAst'
 | 
			
		||||
// import { HorzVert } from './components/Toolbar/HorzVert'
 | 
			
		||||
// import { RemoveConstrainingValues } from './components/Toolbar/RemoveConstrainingValues'
 | 
			
		||||
// import { EqualLength } from './components/Toolbar/EqualLength'
 | 
			
		||||
// import { EqualAngle } from './components/Toolbar/EqualAngle'
 | 
			
		||||
// import { Intersect } from './components/Toolbar/Intersect'
 | 
			
		||||
// import { SetHorzVertDistance } from './components/Toolbar/SetHorzVertDistance'
 | 
			
		||||
// import { SetAngleLength } from './components/Toolbar/setAngleLength'
 | 
			
		||||
// import { SetAbsDistance } from './components/Toolbar/SetAbsDistance'
 | 
			
		||||
// import { SetAngleBetween } from './components/Toolbar/SetAngleBetween'
 | 
			
		||||
import { ToolTip } from './useStore'
 | 
			
		||||
import { Fragment, WheelEvent, useRef, useMemo } from 'react'
 | 
			
		||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
 | 
			
		||||
import { faSearch, faX } from '@fortawesome/free-solid-svg-icons'
 | 
			
		||||
import { Popover, Transition } from '@headlessui/react'
 | 
			
		||||
import styles from './Toolbar.module.css'
 | 
			
		||||
import { v4 as uuidv4 } from 'uuid'
 | 
			
		||||
import { isCursorInSketchCommandRange } from 'lang/util'
 | 
			
		||||
import { ActionIcon } from 'components/ActionIcon'
 | 
			
		||||
import { engineCommandManager } from './lang/std/engineConnection'
 | 
			
		||||
import { useModelingContext } from 'hooks/useModelingContext'
 | 
			
		||||
import { kclManager } from 'lang/KclSinglton'
 | 
			
		||||
 | 
			
		||||
export const sketchButtonClassnames = {
 | 
			
		||||
  background:
 | 
			
		||||
@ -178,24 +165,6 @@ export const Toolbar = () => {
 | 
			
		||||
            Extrude
 | 
			
		||||
          </button>
 | 
			
		||||
        )}
 | 
			
		||||
 | 
			
		||||
        {/* <HorzVert horOrVert="horizontal" />
 | 
			
		||||
        <HorzVert horOrVert="vertical" />
 | 
			
		||||
        <EqualLength />
 | 
			
		||||
        <EqualAngle />
 | 
			
		||||
        <SetHorzVertDistance buttonType="alignEndsVertically" />
 | 
			
		||||
        <SetHorzVertDistance buttonType="setHorzDistance" />
 | 
			
		||||
        <SetAbsDistance buttonType="snapToYAxis" />
 | 
			
		||||
        <SetAbsDistance buttonType="xAbs" />
 | 
			
		||||
        <SetHorzVertDistance buttonType="alignEndsHorizontally" />
 | 
			
		||||
        <SetAbsDistance buttonType="snapToXAxis" />
 | 
			
		||||
        <SetHorzVertDistance buttonType="setVertDistance" />
 | 
			
		||||
        <SetAbsDistance buttonType="yAbs" />
 | 
			
		||||
        <SetAngleLength angleOrLength="setAngle" />
 | 
			
		||||
        <SetAngleLength angleOrLength="setLength" />
 | 
			
		||||
        <Intersect />
 | 
			
		||||
        <RemoveConstrainingValues />
 | 
			
		||||
        <SetAngleBetween /> */}
 | 
			
		||||
      </span>
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -41,6 +41,7 @@ import {
 | 
			
		||||
  setCodeMirrorCursor,
 | 
			
		||||
  useStore,
 | 
			
		||||
} from 'useStore'
 | 
			
		||||
import { applyConstraintIntersect } from './Toolbar/Intersect'
 | 
			
		||||
 | 
			
		||||
type MachineContext<T extends AnyStateMachine> = {
 | 
			
		||||
  state: StateFrom<T>
 | 
			
		||||
@ -372,6 +373,22 @@ export const ModelingMachineProvider = ({
 | 
			
		||||
          ),
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      'Get perpendicular distance info': async ({
 | 
			
		||||
        selectionRanges,
 | 
			
		||||
      }): Promise<SetSelections> => {
 | 
			
		||||
        const { modifiedAst, pathToNodeMap } = await applyConstraintIntersect({
 | 
			
		||||
          selectionRanges,
 | 
			
		||||
        })
 | 
			
		||||
        await kclManager.updateAst(modifiedAst, true)
 | 
			
		||||
        return {
 | 
			
		||||
          selectionType: 'completeSelection',
 | 
			
		||||
          selection: pathMapToSelections(
 | 
			
		||||
            kclManager.ast,
 | 
			
		||||
            selectionRanges,
 | 
			
		||||
            pathToNodeMap
 | 
			
		||||
          ),
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    devTools: true,
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
import { Dialog, Transition } from '@headlessui/react'
 | 
			
		||||
import { Fragment, useState } from 'react'
 | 
			
		||||
import { type InstanceProps, create } from 'react-modal-promise'
 | 
			
		||||
import { Value } from '../lang/wasm'
 | 
			
		||||
import {
 | 
			
		||||
  AvailableVars,
 | 
			
		||||
@ -9,6 +10,28 @@ import {
 | 
			
		||||
  CreateNewVariable,
 | 
			
		||||
} from './AvailableVarsHelpers'
 | 
			
		||||
 | 
			
		||||
type ModalResolve = {
 | 
			
		||||
  value: string
 | 
			
		||||
  sign: number
 | 
			
		||||
  valueNode: Value
 | 
			
		||||
  variableName?: string
 | 
			
		||||
  newVariableInsertIndex: number
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ModalReject = boolean
 | 
			
		||||
 | 
			
		||||
type SetAngleLengthModalProps = InstanceProps<ModalResolve, ModalReject> & {
 | 
			
		||||
  value: number
 | 
			
		||||
  valueName: string
 | 
			
		||||
  shouldCreateVariable?: boolean
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const createSetAngleLengthModal = create<
 | 
			
		||||
  SetAngleLengthModalProps,
 | 
			
		||||
  ModalResolve,
 | 
			
		||||
  ModalReject
 | 
			
		||||
>
 | 
			
		||||
 | 
			
		||||
export const SetAngleLengthModal = ({
 | 
			
		||||
  isOpen,
 | 
			
		||||
  onResolve,
 | 
			
		||||
@ -16,20 +39,7 @@ export const SetAngleLengthModal = ({
 | 
			
		||||
  value: initialValue,
 | 
			
		||||
  valueName,
 | 
			
		||||
  shouldCreateVariable: initialShouldCreateVariable = false,
 | 
			
		||||
}: {
 | 
			
		||||
  isOpen: boolean
 | 
			
		||||
  onResolve: (a: {
 | 
			
		||||
    value: string
 | 
			
		||||
    sign: number
 | 
			
		||||
    valueNode: Value
 | 
			
		||||
    variableName?: string
 | 
			
		||||
    newVariableInsertIndex: number
 | 
			
		||||
  }) => void
 | 
			
		||||
  onReject: (a: any) => void
 | 
			
		||||
  value: number
 | 
			
		||||
  valueName: string
 | 
			
		||||
  shouldCreateVariable: boolean
 | 
			
		||||
}) => {
 | 
			
		||||
}: SetAngleLengthModalProps) => {
 | 
			
		||||
  const [sign, setSign] = useState(Math.sign(Number(initialValue)))
 | 
			
		||||
  const [value, setValue] = useState(String(initialValue * sign))
 | 
			
		||||
  const [shouldCreateVariable, setShouldCreateVariable] = useState(
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
import { Dialog, Transition } from '@headlessui/react'
 | 
			
		||||
import { Fragment, useState } from 'react'
 | 
			
		||||
import { type InstanceProps, create } from 'react-modal-promise'
 | 
			
		||||
import { Value } from '../lang/wasm'
 | 
			
		||||
import {
 | 
			
		||||
  AvailableVars,
 | 
			
		||||
@ -9,6 +10,30 @@ import {
 | 
			
		||||
  CreateNewVariable,
 | 
			
		||||
} from './AvailableVarsHelpers'
 | 
			
		||||
 | 
			
		||||
type ModalResolve = {
 | 
			
		||||
  value: string
 | 
			
		||||
  segName: string
 | 
			
		||||
  valueNode: Value
 | 
			
		||||
  variableName?: string
 | 
			
		||||
  newVariableInsertIndex: number
 | 
			
		||||
  sign: number
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ModalReject = boolean
 | 
			
		||||
 | 
			
		||||
type GetInfoModalProps = InstanceProps<ModalResolve, ModalReject> & {
 | 
			
		||||
  segName: string
 | 
			
		||||
  isSegNameEditable: boolean
 | 
			
		||||
  value?: number
 | 
			
		||||
  initialVariableName: string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const createInfoModal = create<
 | 
			
		||||
  GetInfoModalProps,
 | 
			
		||||
  ModalResolve,
 | 
			
		||||
  ModalReject
 | 
			
		||||
>
 | 
			
		||||
 | 
			
		||||
export const GetInfoModal = ({
 | 
			
		||||
  isOpen,
 | 
			
		||||
  onResolve,
 | 
			
		||||
@ -17,25 +42,12 @@ export const GetInfoModal = ({
 | 
			
		||||
  isSegNameEditable,
 | 
			
		||||
  value: initialValue,
 | 
			
		||||
  initialVariableName,
 | 
			
		||||
}: {
 | 
			
		||||
  isOpen: boolean
 | 
			
		||||
  onResolve: (a: {
 | 
			
		||||
    value: string
 | 
			
		||||
    segName: string
 | 
			
		||||
    valueNode: Value
 | 
			
		||||
    variableName?: string
 | 
			
		||||
    newVariableInsertIndex: number
 | 
			
		||||
    sign: number
 | 
			
		||||
  }) => void
 | 
			
		||||
  onReject: (a: any) => void
 | 
			
		||||
  segName: string
 | 
			
		||||
  isSegNameEditable: boolean
 | 
			
		||||
  value: number
 | 
			
		||||
  initialVariableName: string
 | 
			
		||||
}) => {
 | 
			
		||||
}: GetInfoModalProps) => {
 | 
			
		||||
  const [sign, setSign] = useState(Math.sign(Number(initialValue)))
 | 
			
		||||
  const [segName, setSegName] = useState(initialSegName)
 | 
			
		||||
  const [value, setValue] = useState(String(Math.abs(initialValue)))
 | 
			
		||||
  const [value, setValue] = useState(
 | 
			
		||||
    initialValue === undefined ? '' : String(Math.abs(initialValue))
 | 
			
		||||
  )
 | 
			
		||||
  const [shouldCreateVariable, setShouldCreateVariable] = useState(false)
 | 
			
		||||
 | 
			
		||||
  const {
 | 
			
		||||
 | 
			
		||||
@ -4,19 +4,26 @@ import { useCalc, CreateNewVariable } from './AvailableVarsHelpers'
 | 
			
		||||
import { ActionButton } from './ActionButton'
 | 
			
		||||
import { faPlus } from '@fortawesome/free-solid-svg-icons'
 | 
			
		||||
import { toast } from 'react-hot-toast'
 | 
			
		||||
import { type InstanceProps, create } from 'react-modal-promise'
 | 
			
		||||
 | 
			
		||||
type ModalResolve = { variableName: string }
 | 
			
		||||
type ModalReject = boolean
 | 
			
		||||
type SetVarNameModalProps = InstanceProps<ModalResolve, ModalReject> & {
 | 
			
		||||
  valueName: string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const createSetVarNameModal = create<
 | 
			
		||||
  SetVarNameModalProps,
 | 
			
		||||
  ModalResolve,
 | 
			
		||||
  ModalReject
 | 
			
		||||
>
 | 
			
		||||
 | 
			
		||||
export const SetVarNameModal = ({
 | 
			
		||||
  isOpen,
 | 
			
		||||
  onResolve,
 | 
			
		||||
  onReject,
 | 
			
		||||
  valueName,
 | 
			
		||||
}: {
 | 
			
		||||
  isOpen: boolean
 | 
			
		||||
  onResolve: (a: { variableName?: string }) => void
 | 
			
		||||
  onReject: (a: any) => void
 | 
			
		||||
  value: number
 | 
			
		||||
  valueName: string
 | 
			
		||||
}) => {
 | 
			
		||||
}: SetVarNameModalProps) => {
 | 
			
		||||
  const { isNewVariableNameUnique, newVariableName, setNewVariableName } =
 | 
			
		||||
    useCalc({ value: '', initialVariableName: valueName })
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,102 +1,78 @@
 | 
			
		||||
import { useState, useEffect } from 'react'
 | 
			
		||||
import { toolTips, useStore } from '../../useStore'
 | 
			
		||||
import { Value, VariableDeclarator } from '../../lang/wasm'
 | 
			
		||||
import { Selections, toolTips } from '../../useStore'
 | 
			
		||||
import { Program, Value, VariableDeclarator } from '../../lang/wasm'
 | 
			
		||||
import {
 | 
			
		||||
  getNodePathFromSourceRange,
 | 
			
		||||
  getNodeFromPath,
 | 
			
		||||
} from '../../lang/queryAst'
 | 
			
		||||
import { isSketchVariablesLinked } from '../../lang/std/sketchConstraints'
 | 
			
		||||
import {
 | 
			
		||||
  TransformInfo,
 | 
			
		||||
  transformSecondarySketchLinesTagFirst,
 | 
			
		||||
  getTransformInfos,
 | 
			
		||||
  PathToNodeMap,
 | 
			
		||||
} from '../../lang/std/sketchcombos'
 | 
			
		||||
import { ActionIcon } from 'components/ActionIcon'
 | 
			
		||||
import { sketchButtonClassnames } from 'Toolbar'
 | 
			
		||||
import { kclManager } from 'lang/KclSinglton'
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
export const EqualAngle = () => {
 | 
			
		||||
  const { guiMode, selectionRanges, setCursor } = useStore((s) => ({
 | 
			
		||||
    guiMode: s.guiMode,
 | 
			
		||||
    selectionRanges: s.selectionRanges,
 | 
			
		||||
    setCursor: s.setCursor,
 | 
			
		||||
  }))
 | 
			
		||||
  const [enableEqual, setEnableEqual] = useState(false)
 | 
			
		||||
  const [transformInfos, setTransformInfos] = useState<TransformInfo[]>()
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const paths = selectionRanges.codeBasedSelections.map(({ range }) =>
 | 
			
		||||
      getNodePathFromSourceRange(kclManager.ast, range)
 | 
			
		||||
    )
 | 
			
		||||
    const nodes = paths.map(
 | 
			
		||||
      (pathToNode) => getNodeFromPath<Value>(kclManager.ast, pathToNode).node
 | 
			
		||||
    )
 | 
			
		||||
    const varDecs = paths.map(
 | 
			
		||||
      (pathToNode) =>
 | 
			
		||||
        getNodeFromPath<VariableDeclarator>(
 | 
			
		||||
          kclManager.ast,
 | 
			
		||||
          pathToNode,
 | 
			
		||||
          'VariableDeclarator'
 | 
			
		||||
        )?.node
 | 
			
		||||
    )
 | 
			
		||||
    const primaryLine = varDecs[0]
 | 
			
		||||
    const secondaryVarDecs = varDecs.slice(1)
 | 
			
		||||
    const isOthersLinkedToPrimary = secondaryVarDecs.every((secondary) =>
 | 
			
		||||
      isSketchVariablesLinked(secondary, primaryLine, kclManager.ast)
 | 
			
		||||
    )
 | 
			
		||||
    const isAllTooltips = nodes.every(
 | 
			
		||||
      (node) =>
 | 
			
		||||
        node?.type === 'CallExpression' &&
 | 
			
		||||
        toolTips.includes(node.callee.name as any)
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    const theTransforms = getTransformInfos(
 | 
			
		||||
      {
 | 
			
		||||
        ...selectionRanges,
 | 
			
		||||
        codeBasedSelections: selectionRanges.codeBasedSelections.slice(1),
 | 
			
		||||
      },
 | 
			
		||||
      kclManager.ast,
 | 
			
		||||
      'equalAngle'
 | 
			
		||||
    )
 | 
			
		||||
    setTransformInfos(theTransforms)
 | 
			
		||||
 | 
			
		||||
    const _enableEqual =
 | 
			
		||||
      !!secondaryVarDecs.length &&
 | 
			
		||||
      isAllTooltips &&
 | 
			
		||||
      isOthersLinkedToPrimary &&
 | 
			
		||||
      theTransforms.every(Boolean)
 | 
			
		||||
    setEnableEqual(_enableEqual)
 | 
			
		||||
  }, [guiMode, selectionRanges])
 | 
			
		||||
  if (guiMode.mode !== 'sketch') return null
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <button
 | 
			
		||||
      onClick={async () => {
 | 
			
		||||
        if (!transformInfos) return
 | 
			
		||||
        const { modifiedAst, pathToNodeMap } =
 | 
			
		||||
          transformSecondarySketchLinesTagFirst({
 | 
			
		||||
            ast: kclManager.ast,
 | 
			
		||||
            selectionRanges,
 | 
			
		||||
            transformInfos,
 | 
			
		||||
            programMemory: kclManager.programMemory,
 | 
			
		||||
          })
 | 
			
		||||
        kclManager.updateAst(modifiedAst, true, {
 | 
			
		||||
          callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
 | 
			
		||||
        })
 | 
			
		||||
      }}
 | 
			
		||||
      disabled={!enableEqual}
 | 
			
		||||
      title="Parallel (or equal angle)"
 | 
			
		||||
      className="group"
 | 
			
		||||
    >
 | 
			
		||||
      <ActionIcon
 | 
			
		||||
        icon="parallel"
 | 
			
		||||
        className="!p-0.5"
 | 
			
		||||
        bgClassName={sketchButtonClassnames.background}
 | 
			
		||||
        iconClassName={sketchButtonClassnames.icon}
 | 
			
		||||
        size="md"
 | 
			
		||||
      />
 | 
			
		||||
      Parallel
 | 
			
		||||
    </button>
 | 
			
		||||
export function equalAngleInfo({
 | 
			
		||||
  selectionRanges,
 | 
			
		||||
}: {
 | 
			
		||||
  selectionRanges: Selections
 | 
			
		||||
}) {
 | 
			
		||||
  const paths = selectionRanges.codeBasedSelections.map(({ range }) =>
 | 
			
		||||
    getNodePathFromSourceRange(kclManager.ast, range)
 | 
			
		||||
  )
 | 
			
		||||
  const nodes = paths.map(
 | 
			
		||||
    (pathToNode) => getNodeFromPath<Value>(kclManager.ast, pathToNode).node
 | 
			
		||||
  )
 | 
			
		||||
  const varDecs = paths.map(
 | 
			
		||||
    (pathToNode) =>
 | 
			
		||||
      getNodeFromPath<VariableDeclarator>(
 | 
			
		||||
        kclManager.ast,
 | 
			
		||||
        pathToNode,
 | 
			
		||||
        'VariableDeclarator'
 | 
			
		||||
      )?.node
 | 
			
		||||
  )
 | 
			
		||||
  const primaryLine = varDecs[0]
 | 
			
		||||
  const secondaryVarDecs = varDecs.slice(1)
 | 
			
		||||
  const isOthersLinkedToPrimary = secondaryVarDecs.every((secondary) =>
 | 
			
		||||
    isSketchVariablesLinked(secondary, primaryLine, kclManager.ast)
 | 
			
		||||
  )
 | 
			
		||||
  const isAllTooltips = nodes.every(
 | 
			
		||||
    (node) =>
 | 
			
		||||
      node?.type === 'CallExpression' &&
 | 
			
		||||
      toolTips.includes(node.callee.name as any)
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  const transforms = getTransformInfos(
 | 
			
		||||
    {
 | 
			
		||||
      ...selectionRanges,
 | 
			
		||||
      codeBasedSelections: selectionRanges.codeBasedSelections.slice(1),
 | 
			
		||||
    },
 | 
			
		||||
    kclManager.ast,
 | 
			
		||||
    'equalAngle'
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  const enabled =
 | 
			
		||||
    !!secondaryVarDecs.length &&
 | 
			
		||||
    isAllTooltips &&
 | 
			
		||||
    isOthersLinkedToPrimary &&
 | 
			
		||||
    transforms.every(Boolean)
 | 
			
		||||
  return { enabled, transforms }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function applyConstraintEqualAngle({
 | 
			
		||||
  selectionRanges,
 | 
			
		||||
}: {
 | 
			
		||||
  selectionRanges: Selections
 | 
			
		||||
}): {
 | 
			
		||||
  modifiedAst: Program
 | 
			
		||||
  pathToNodeMap: PathToNodeMap
 | 
			
		||||
} {
 | 
			
		||||
  const { transforms } = equalAngleInfo({ selectionRanges })
 | 
			
		||||
  const { modifiedAst, pathToNodeMap } = transformSecondarySketchLinesTagFirst({
 | 
			
		||||
    ast: kclManager.ast,
 | 
			
		||||
    selectionRanges,
 | 
			
		||||
    transformInfos: transforms,
 | 
			
		||||
    programMemory: kclManager.programMemory,
 | 
			
		||||
  })
 | 
			
		||||
  return { modifiedAst, pathToNodeMap }
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,4 @@
 | 
			
		||||
import { useState, useEffect } from 'react'
 | 
			
		||||
import { Selections, toolTips, useStore } from '../../useStore'
 | 
			
		||||
import { Selections, toolTips } from '../../useStore'
 | 
			
		||||
import { Program, Value, VariableDeclarator } from '../../lang/wasm'
 | 
			
		||||
import {
 | 
			
		||||
  getNodePathFromSourceRange,
 | 
			
		||||
@ -7,63 +6,12 @@ import {
 | 
			
		||||
} from '../../lang/queryAst'
 | 
			
		||||
import { isSketchVariablesLinked } from '../../lang/std/sketchConstraints'
 | 
			
		||||
import {
 | 
			
		||||
  TransformInfo,
 | 
			
		||||
  transformSecondarySketchLinesTagFirst,
 | 
			
		||||
  getTransformInfos,
 | 
			
		||||
  PathToNodeMap,
 | 
			
		||||
} from '../../lang/std/sketchcombos'
 | 
			
		||||
import { ActionIcon } from 'components/ActionIcon'
 | 
			
		||||
import { sketchButtonClassnames } from 'Toolbar'
 | 
			
		||||
import { kclManager } from 'lang/KclSinglton'
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
export const EqualLength = () => {
 | 
			
		||||
  const { guiMode, selectionRanges, setCursor } = useStore((s) => ({
 | 
			
		||||
    guiMode: s.guiMode,
 | 
			
		||||
    selectionRanges: s.selectionRanges,
 | 
			
		||||
    setCursor: s.setCursor,
 | 
			
		||||
  }))
 | 
			
		||||
  const [enableEqual, setEnableEqual] = useState(false)
 | 
			
		||||
  const [transformInfos, setTransformInfos] = useState<TransformInfo[]>()
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const { enabled, transforms } = setEqualLengthInfo({ selectionRanges })
 | 
			
		||||
 | 
			
		||||
    setTransformInfos(transforms)
 | 
			
		||||
    setEnableEqual(enabled)
 | 
			
		||||
  }, [guiMode, selectionRanges])
 | 
			
		||||
  if (guiMode.mode !== 'sketch') return null
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <button
 | 
			
		||||
      onClick={() => {
 | 
			
		||||
        if (!transformInfos) return
 | 
			
		||||
        const { modifiedAst, pathToNodeMap } =
 | 
			
		||||
          transformSecondarySketchLinesTagFirst({
 | 
			
		||||
            ast: kclManager.ast,
 | 
			
		||||
            selectionRanges,
 | 
			
		||||
            transformInfos,
 | 
			
		||||
            programMemory: kclManager.programMemory,
 | 
			
		||||
          })
 | 
			
		||||
        kclManager.updateAst(modifiedAst, true, {
 | 
			
		||||
          callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
 | 
			
		||||
        })
 | 
			
		||||
      }}
 | 
			
		||||
      disabled={!enableEqual}
 | 
			
		||||
      className="group"
 | 
			
		||||
      title="Equal Length"
 | 
			
		||||
    >
 | 
			
		||||
      <ActionIcon
 | 
			
		||||
        icon="equal"
 | 
			
		||||
        className="!p-0.5"
 | 
			
		||||
        bgClassName={sketchButtonClassnames.background}
 | 
			
		||||
        iconClassName={sketchButtonClassnames.icon}
 | 
			
		||||
        size="md"
 | 
			
		||||
      />
 | 
			
		||||
      Equal Length
 | 
			
		||||
    </button>
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
export function setEqualLengthInfo({
 | 
			
		||||
  selectionRanges,
 | 
			
		||||
}: {
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,4 @@
 | 
			
		||||
import { useState, useEffect } from 'react'
 | 
			
		||||
import { toolTips, useStore } from '../../useStore'
 | 
			
		||||
import { toolTips } from '../../useStore'
 | 
			
		||||
import { Program, ProgramMemory, Value } from '../../lang/wasm'
 | 
			
		||||
import {
 | 
			
		||||
  getNodePathFromSourceRange,
 | 
			
		||||
@ -7,67 +6,12 @@ import {
 | 
			
		||||
} from '../../lang/queryAst'
 | 
			
		||||
import {
 | 
			
		||||
  PathToNodeMap,
 | 
			
		||||
  TransformInfo,
 | 
			
		||||
  getTransformInfos,
 | 
			
		||||
  transformAstSketchLines,
 | 
			
		||||
} from '../../lang/std/sketchcombos'
 | 
			
		||||
import { ActionIcon } from 'components/ActionIcon'
 | 
			
		||||
import { sketchButtonClassnames } from 'Toolbar'
 | 
			
		||||
import { kclManager } from 'lang/KclSinglton'
 | 
			
		||||
import { Selections } from 'useStore'
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
export const HorzVert = ({
 | 
			
		||||
  horOrVert,
 | 
			
		||||
}: {
 | 
			
		||||
  horOrVert: 'vertical' | 'horizontal'
 | 
			
		||||
}) => {
 | 
			
		||||
  const { guiMode, selectionRanges, setCursor } = useStore((s) => ({
 | 
			
		||||
    guiMode: s.guiMode,
 | 
			
		||||
    selectionRanges: s.selectionRanges,
 | 
			
		||||
    setCursor: s.setCursor,
 | 
			
		||||
  }))
 | 
			
		||||
  const [enableHorz, setEnableHorz] = useState(false)
 | 
			
		||||
  const [transformInfos, setTransformInfos] = useState<TransformInfo[]>()
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const { enabled, transforms } = horzVertInfo(selectionRanges, horOrVert)
 | 
			
		||||
    setTransformInfos(transforms)
 | 
			
		||||
    setEnableHorz(enabled)
 | 
			
		||||
  }, [guiMode, selectionRanges])
 | 
			
		||||
  if (guiMode.mode !== 'sketch') return null
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <button
 | 
			
		||||
      onClick={() => {
 | 
			
		||||
        if (!transformInfos) return
 | 
			
		||||
        const { modifiedAst, pathToNodeMap } = transformAstSketchLines({
 | 
			
		||||
          ast: kclManager.ast,
 | 
			
		||||
          selectionRanges,
 | 
			
		||||
          transformInfos,
 | 
			
		||||
          programMemory: kclManager.programMemory,
 | 
			
		||||
          referenceSegName: '',
 | 
			
		||||
        })
 | 
			
		||||
        kclManager.updateAst(modifiedAst, true, {
 | 
			
		||||
          callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
 | 
			
		||||
        })
 | 
			
		||||
      }}
 | 
			
		||||
      disabled={!enableHorz}
 | 
			
		||||
      className="group"
 | 
			
		||||
      title={horOrVert === 'horizontal' ? 'Horizontal' : 'Vertical'}
 | 
			
		||||
    >
 | 
			
		||||
      <ActionIcon
 | 
			
		||||
        icon={horOrVert === 'horizontal' ? 'horizontal' : 'vertical'}
 | 
			
		||||
        className="!p-0.5"
 | 
			
		||||
        bgClassName={sketchButtonClassnames.background}
 | 
			
		||||
        iconClassName={sketchButtonClassnames.icon}
 | 
			
		||||
        size="md"
 | 
			
		||||
      />
 | 
			
		||||
      {horOrVert === 'horizontal' ? 'Horizontal' : 'Vertical'}
 | 
			
		||||
    </button>
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
export function horzVertInfo(
 | 
			
		||||
  selectionRanges: Selections,
 | 
			
		||||
  horOrVert: 'vertical' | 'horizontal'
 | 
			
		||||
@ -110,7 +54,4 @@ export function applyConstraintHorzVert(
 | 
			
		||||
    programMemory,
 | 
			
		||||
    referenceSegName: '',
 | 
			
		||||
  })
 | 
			
		||||
  // kclManager.updateAst(modifiedAst, true, {
 | 
			
		||||
  //   callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
 | 
			
		||||
  // })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,5 @@
 | 
			
		||||
import { useState, useEffect } from 'react'
 | 
			
		||||
import { create } from 'react-modal-promise'
 | 
			
		||||
import { toolTips, useStore } from '../../useStore'
 | 
			
		||||
import { BinaryPart, Value, VariableDeclarator } from '../../lang/wasm'
 | 
			
		||||
import { Selections, toolTips } from '../../useStore'
 | 
			
		||||
import { BinaryPart, Program, Value, VariableDeclarator } from '../../lang/wasm'
 | 
			
		||||
import {
 | 
			
		||||
  getNodePathFromSourceRange,
 | 
			
		||||
  getNodeFromPath,
 | 
			
		||||
@ -9,181 +7,170 @@ import {
 | 
			
		||||
} from '../../lang/queryAst'
 | 
			
		||||
import { isSketchVariablesLinked } from '../../lang/std/sketchConstraints'
 | 
			
		||||
import {
 | 
			
		||||
  TransformInfo,
 | 
			
		||||
  transformSecondarySketchLinesTagFirst,
 | 
			
		||||
  getTransformInfos,
 | 
			
		||||
  PathToNodeMap,
 | 
			
		||||
} from '../../lang/std/sketchcombos'
 | 
			
		||||
import { GetInfoModal } from '../SetHorVertDistanceModal'
 | 
			
		||||
import { GetInfoModal, createInfoModal } from '../SetHorVertDistanceModal'
 | 
			
		||||
import { createVariableDeclaration } from '../../lang/modifyAst'
 | 
			
		||||
import { removeDoubleNegatives } from '../AvailableVarsHelpers'
 | 
			
		||||
import { kclManager } from 'lang/KclSinglton'
 | 
			
		||||
 | 
			
		||||
const getModalInfo = create(GetInfoModal as any)
 | 
			
		||||
const getModalInfo = createInfoModal(GetInfoModal)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
export const Intersect = () => {
 | 
			
		||||
  const { guiMode, selectionRanges, setCursor } = useStore((s) => ({
 | 
			
		||||
    guiMode: s.guiMode,
 | 
			
		||||
    selectionRanges: s.selectionRanges,
 | 
			
		||||
    setCursor: s.setCursor,
 | 
			
		||||
  }))
 | 
			
		||||
  const [enable, setEnable] = useState(false)
 | 
			
		||||
  const [transformInfos, setTransformInfos] = useState<TransformInfo[]>()
 | 
			
		||||
  const [forecdSelectionRanges, setForcedSelectionRanges] =
 | 
			
		||||
    useState<typeof selectionRanges>()
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    if (selectionRanges.codeBasedSelections.length < 2) {
 | 
			
		||||
      setEnable(false)
 | 
			
		||||
      setForcedSelectionRanges({ ...selectionRanges })
 | 
			
		||||
      return
 | 
			
		||||
export function intersectInfo({
 | 
			
		||||
  selectionRanges,
 | 
			
		||||
}: {
 | 
			
		||||
  selectionRanges: Selections
 | 
			
		||||
}) {
 | 
			
		||||
  if (selectionRanges.codeBasedSelections.length < 2) {
 | 
			
		||||
    return {
 | 
			
		||||
      enabled: false,
 | 
			
		||||
      transforms: [],
 | 
			
		||||
      forcedSelectionRanges: { ...selectionRanges },
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
    const previousSegment =
 | 
			
		||||
      selectionRanges.codeBasedSelections.length > 1 &&
 | 
			
		||||
      isLinesParallelAndConstrained(
 | 
			
		||||
        kclManager.ast,
 | 
			
		||||
        kclManager.programMemory,
 | 
			
		||||
        selectionRanges.codeBasedSelections[0],
 | 
			
		||||
        selectionRanges.codeBasedSelections[1]
 | 
			
		||||
      )
 | 
			
		||||
    const shouldUsePreviousSegment =
 | 
			
		||||
      selectionRanges.codeBasedSelections?.[1]?.type !== 'line-end' &&
 | 
			
		||||
      previousSegment &&
 | 
			
		||||
      previousSegment.isParallelAndConstrained
 | 
			
		||||
 | 
			
		||||
    const _forcedSelectionRanges: typeof selectionRanges = {
 | 
			
		||||
      ...selectionRanges,
 | 
			
		||||
      codeBasedSelections: [
 | 
			
		||||
        selectionRanges.codeBasedSelections?.[0],
 | 
			
		||||
        shouldUsePreviousSegment
 | 
			
		||||
          ? {
 | 
			
		||||
              range: previousSegment.sourceRange,
 | 
			
		||||
              type: 'line-end',
 | 
			
		||||
            }
 | 
			
		||||
          : selectionRanges.codeBasedSelections?.[1],
 | 
			
		||||
      ],
 | 
			
		||||
    }
 | 
			
		||||
    setForcedSelectionRanges(_forcedSelectionRanges)
 | 
			
		||||
 | 
			
		||||
    const paths = _forcedSelectionRanges.codeBasedSelections.map(({ range }) =>
 | 
			
		||||
      getNodePathFromSourceRange(kclManager.ast, range)
 | 
			
		||||
    )
 | 
			
		||||
    const nodes = paths.map(
 | 
			
		||||
      (pathToNode) => getNodeFromPath<Value>(kclManager.ast, pathToNode).node
 | 
			
		||||
    )
 | 
			
		||||
    const varDecs = paths.map(
 | 
			
		||||
      (pathToNode) =>
 | 
			
		||||
        getNodeFromPath<VariableDeclarator>(
 | 
			
		||||
          kclManager.ast,
 | 
			
		||||
          pathToNode,
 | 
			
		||||
          'VariableDeclarator'
 | 
			
		||||
        )?.node
 | 
			
		||||
    )
 | 
			
		||||
    const primaryLine = varDecs[0]
 | 
			
		||||
    const secondaryVarDecs = varDecs.slice(1)
 | 
			
		||||
    const isOthersLinkedToPrimary = secondaryVarDecs.every((secondary) =>
 | 
			
		||||
      isSketchVariablesLinked(secondary, primaryLine, kclManager.ast)
 | 
			
		||||
    )
 | 
			
		||||
    const isAllTooltips = nodes.every(
 | 
			
		||||
      (node) =>
 | 
			
		||||
        node?.type === 'CallExpression' &&
 | 
			
		||||
        [
 | 
			
		||||
          ...toolTips,
 | 
			
		||||
          'startSketchAt', // TODO probably a better place for this to live
 | 
			
		||||
        ].includes(node.callee.name as any)
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    const theTransforms = getTransformInfos(
 | 
			
		||||
      {
 | 
			
		||||
        ...selectionRanges,
 | 
			
		||||
        codeBasedSelections:
 | 
			
		||||
          _forcedSelectionRanges.codeBasedSelections.slice(1),
 | 
			
		||||
      },
 | 
			
		||||
  const previousSegment =
 | 
			
		||||
    selectionRanges.codeBasedSelections.length > 1 &&
 | 
			
		||||
    isLinesParallelAndConstrained(
 | 
			
		||||
      kclManager.ast,
 | 
			
		||||
      'intersect'
 | 
			
		||||
      kclManager.programMemory,
 | 
			
		||||
      selectionRanges.codeBasedSelections[0],
 | 
			
		||||
      selectionRanges.codeBasedSelections[1]
 | 
			
		||||
    )
 | 
			
		||||
    setTransformInfos(theTransforms)
 | 
			
		||||
  const shouldUsePreviousSegment =
 | 
			
		||||
    selectionRanges.codeBasedSelections?.[1]?.type !== 'line-end' &&
 | 
			
		||||
    previousSegment &&
 | 
			
		||||
    previousSegment.isParallelAndConstrained
 | 
			
		||||
 | 
			
		||||
    const _enableEqual =
 | 
			
		||||
      secondaryVarDecs.length === 1 &&
 | 
			
		||||
      isAllTooltips &&
 | 
			
		||||
      isOthersLinkedToPrimary &&
 | 
			
		||||
      theTransforms.every(Boolean) &&
 | 
			
		||||
      _forcedSelectionRanges?.codeBasedSelections?.[1]?.type === 'line-end'
 | 
			
		||||
    setEnable(_enableEqual)
 | 
			
		||||
  }, [guiMode, selectionRanges])
 | 
			
		||||
  if (guiMode.mode !== 'sketch') return null
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <button
 | 
			
		||||
      onClick={async () => {
 | 
			
		||||
        if (!(transformInfos && forecdSelectionRanges)) return
 | 
			
		||||
        const { modifiedAst, tagInfo, valueUsedInTransform, pathToNodeMap } =
 | 
			
		||||
          transformSecondarySketchLinesTagFirst({
 | 
			
		||||
            ast: JSON.parse(JSON.stringify(kclManager.ast)),
 | 
			
		||||
            selectionRanges: forecdSelectionRanges,
 | 
			
		||||
            transformInfos,
 | 
			
		||||
            programMemory: kclManager.programMemory,
 | 
			
		||||
          })
 | 
			
		||||
        const {
 | 
			
		||||
          segName,
 | 
			
		||||
          value,
 | 
			
		||||
          valueNode,
 | 
			
		||||
          variableName,
 | 
			
		||||
          newVariableInsertIndex,
 | 
			
		||||
          sign,
 | 
			
		||||
        }: {
 | 
			
		||||
          segName: string
 | 
			
		||||
          value: number
 | 
			
		||||
          valueNode: Value
 | 
			
		||||
          variableName?: string
 | 
			
		||||
          newVariableInsertIndex: number
 | 
			
		||||
          sign: number
 | 
			
		||||
        } = await getModalInfo({
 | 
			
		||||
          segName: tagInfo?.tag,
 | 
			
		||||
          isSegNameEditable: !tagInfo?.isTagExisting,
 | 
			
		||||
          value: valueUsedInTransform,
 | 
			
		||||
          initialVariableName: 'offset',
 | 
			
		||||
        } as any)
 | 
			
		||||
        if (segName === tagInfo?.tag && value === valueUsedInTransform) {
 | 
			
		||||
          kclManager.updateAst(modifiedAst, true, {
 | 
			
		||||
            callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
 | 
			
		||||
          })
 | 
			
		||||
        } else {
 | 
			
		||||
          // transform again but forcing certain values
 | 
			
		||||
          const finalValue = removeDoubleNegatives(
 | 
			
		||||
            valueNode as BinaryPart,
 | 
			
		||||
            sign,
 | 
			
		||||
            variableName
 | 
			
		||||
          )
 | 
			
		||||
          const { modifiedAst: _modifiedAst, pathToNodeMap } =
 | 
			
		||||
            transformSecondarySketchLinesTagFirst({
 | 
			
		||||
              ast: kclManager.ast,
 | 
			
		||||
              selectionRanges: forecdSelectionRanges,
 | 
			
		||||
              transformInfos,
 | 
			
		||||
              programMemory: kclManager.programMemory,
 | 
			
		||||
              forceSegName: segName,
 | 
			
		||||
              forceValueUsedInTransform: finalValue,
 | 
			
		||||
            })
 | 
			
		||||
          if (variableName) {
 | 
			
		||||
            const newBody = [..._modifiedAst.body]
 | 
			
		||||
            newBody.splice(
 | 
			
		||||
              newVariableInsertIndex,
 | 
			
		||||
              0,
 | 
			
		||||
              createVariableDeclaration(variableName, valueNode)
 | 
			
		||||
            )
 | 
			
		||||
            _modifiedAst.body = newBody
 | 
			
		||||
  const _forcedSelectionRanges: typeof selectionRanges = {
 | 
			
		||||
    ...selectionRanges,
 | 
			
		||||
    codeBasedSelections: [
 | 
			
		||||
      selectionRanges.codeBasedSelections?.[0],
 | 
			
		||||
      shouldUsePreviousSegment
 | 
			
		||||
        ? {
 | 
			
		||||
            range: previousSegment.sourceRange,
 | 
			
		||||
            type: 'line-end',
 | 
			
		||||
          }
 | 
			
		||||
          kclManager.updateAst(_modifiedAst, true, {
 | 
			
		||||
            callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
 | 
			
		||||
          })
 | 
			
		||||
        }
 | 
			
		||||
      }}
 | 
			
		||||
      disabled={!enable}
 | 
			
		||||
      title="Set Perpendicular Distance"
 | 
			
		||||
    >
 | 
			
		||||
      Set Perpendicular Distance
 | 
			
		||||
    </button>
 | 
			
		||||
        : selectionRanges.codeBasedSelections?.[1],
 | 
			
		||||
    ],
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const paths = _forcedSelectionRanges.codeBasedSelections.map(({ range }) =>
 | 
			
		||||
    getNodePathFromSourceRange(kclManager.ast, range)
 | 
			
		||||
  )
 | 
			
		||||
  const nodes = paths.map(
 | 
			
		||||
    (pathToNode) => getNodeFromPath<Value>(kclManager.ast, pathToNode).node
 | 
			
		||||
  )
 | 
			
		||||
  const varDecs = paths.map(
 | 
			
		||||
    (pathToNode) =>
 | 
			
		||||
      getNodeFromPath<VariableDeclarator>(
 | 
			
		||||
        kclManager.ast,
 | 
			
		||||
        pathToNode,
 | 
			
		||||
        'VariableDeclarator'
 | 
			
		||||
      )?.node
 | 
			
		||||
  )
 | 
			
		||||
  const primaryLine = varDecs[0]
 | 
			
		||||
  const secondaryVarDecs = varDecs.slice(1)
 | 
			
		||||
  const isOthersLinkedToPrimary = secondaryVarDecs.every((secondary) =>
 | 
			
		||||
    isSketchVariablesLinked(secondary, primaryLine, kclManager.ast)
 | 
			
		||||
  )
 | 
			
		||||
  const isAllTooltips = nodes.every(
 | 
			
		||||
    (node) =>
 | 
			
		||||
      node?.type === 'CallExpression' &&
 | 
			
		||||
      [
 | 
			
		||||
        ...toolTips,
 | 
			
		||||
        'startSketchAt', // TODO probably a better place for this to live
 | 
			
		||||
      ].includes(node.callee.name as any)
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  const theTransforms = getTransformInfos(
 | 
			
		||||
    {
 | 
			
		||||
      ...selectionRanges,
 | 
			
		||||
      codeBasedSelections: _forcedSelectionRanges.codeBasedSelections.slice(1),
 | 
			
		||||
    },
 | 
			
		||||
    kclManager.ast,
 | 
			
		||||
    'intersect'
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  const _enableEqual =
 | 
			
		||||
    secondaryVarDecs.length === 1 &&
 | 
			
		||||
    isAllTooltips &&
 | 
			
		||||
    isOthersLinkedToPrimary &&
 | 
			
		||||
    theTransforms.every(Boolean) &&
 | 
			
		||||
    _forcedSelectionRanges?.codeBasedSelections?.[1]?.type === 'line-end'
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    enabled: _enableEqual,
 | 
			
		||||
    transforms: theTransforms,
 | 
			
		||||
    forcedSelectionRanges: _forcedSelectionRanges,
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function applyConstraintIntersect({
 | 
			
		||||
  selectionRanges,
 | 
			
		||||
}: {
 | 
			
		||||
  selectionRanges: Selections
 | 
			
		||||
}): Promise<{
 | 
			
		||||
  modifiedAst: Program
 | 
			
		||||
  pathToNodeMap: PathToNodeMap
 | 
			
		||||
}> {
 | 
			
		||||
  const { transforms, forcedSelectionRanges } = intersectInfo({
 | 
			
		||||
    selectionRanges,
 | 
			
		||||
  })
 | 
			
		||||
  const { modifiedAst, tagInfo, valueUsedInTransform, pathToNodeMap } =
 | 
			
		||||
    transformSecondarySketchLinesTagFirst({
 | 
			
		||||
      ast: JSON.parse(JSON.stringify(kclManager.ast)),
 | 
			
		||||
      selectionRanges: forcedSelectionRanges,
 | 
			
		||||
      transformInfos: transforms,
 | 
			
		||||
      programMemory: kclManager.programMemory,
 | 
			
		||||
    })
 | 
			
		||||
  const {
 | 
			
		||||
    segName,
 | 
			
		||||
    value,
 | 
			
		||||
    valueNode,
 | 
			
		||||
    variableName,
 | 
			
		||||
    newVariableInsertIndex,
 | 
			
		||||
    sign,
 | 
			
		||||
  } = await getModalInfo({
 | 
			
		||||
    segName: tagInfo?.tag,
 | 
			
		||||
    isSegNameEditable: !tagInfo?.isTagExisting,
 | 
			
		||||
    value: valueUsedInTransform,
 | 
			
		||||
    initialVariableName: 'offset',
 | 
			
		||||
  })
 | 
			
		||||
  if (segName === tagInfo?.tag && Number(value) === valueUsedInTransform) {
 | 
			
		||||
    return {
 | 
			
		||||
      modifiedAst,
 | 
			
		||||
      pathToNodeMap,
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  // transform again but forcing certain values
 | 
			
		||||
  const finalValue = removeDoubleNegatives(
 | 
			
		||||
    valueNode as BinaryPart,
 | 
			
		||||
    sign,
 | 
			
		||||
    variableName
 | 
			
		||||
  )
 | 
			
		||||
  const { modifiedAst: _modifiedAst, pathToNodeMap: _pathToNodeMap } =
 | 
			
		||||
    transformSecondarySketchLinesTagFirst({
 | 
			
		||||
      ast: kclManager.ast,
 | 
			
		||||
      selectionRanges: forcedSelectionRanges,
 | 
			
		||||
      transformInfos: transforms,
 | 
			
		||||
      programMemory: kclManager.programMemory,
 | 
			
		||||
      forceSegName: segName,
 | 
			
		||||
      forceValueUsedInTransform: finalValue,
 | 
			
		||||
    })
 | 
			
		||||
  if (variableName) {
 | 
			
		||||
    const newBody = [..._modifiedAst.body]
 | 
			
		||||
    newBody.splice(
 | 
			
		||||
      newVariableInsertIndex,
 | 
			
		||||
      0,
 | 
			
		||||
      createVariableDeclaration(variableName, valueNode)
 | 
			
		||||
    )
 | 
			
		||||
    _modifiedAst.body = newBody
 | 
			
		||||
  }
 | 
			
		||||
  return {
 | 
			
		||||
    modifiedAst: _modifiedAst,
 | 
			
		||||
    pathToNodeMap: _pathToNodeMap,
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
@ -1,75 +1,62 @@
 | 
			
		||||
import { useState, useEffect } from 'react'
 | 
			
		||||
import { toolTips, useStore } from '../../useStore'
 | 
			
		||||
import { Value } from '../../lang/wasm'
 | 
			
		||||
import { Selections, toolTips } from '../../useStore'
 | 
			
		||||
import { Program, Value } from '../../lang/wasm'
 | 
			
		||||
import {
 | 
			
		||||
  getNodePathFromSourceRange,
 | 
			
		||||
  getNodeFromPath,
 | 
			
		||||
} from '../../lang/queryAst'
 | 
			
		||||
import {
 | 
			
		||||
  TransformInfo,
 | 
			
		||||
  PathToNodeMap,
 | 
			
		||||
  getRemoveConstraintsTransforms,
 | 
			
		||||
  transformAstSketchLines,
 | 
			
		||||
} from '../../lang/std/sketchcombos'
 | 
			
		||||
import { kclManager } from 'lang/KclSinglton'
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
export const RemoveConstrainingValues = () => {
 | 
			
		||||
  const { guiMode, selectionRanges, setCursor } = useStore((s) => ({
 | 
			
		||||
    guiMode: s.guiMode,
 | 
			
		||||
    selectionRanges: s.selectionRanges,
 | 
			
		||||
    setCursor: s.setCursor,
 | 
			
		||||
  }))
 | 
			
		||||
  const [enableHorz, setEnableHorz] = useState(false)
 | 
			
		||||
  const [transformInfos, setTransformInfos] = useState<TransformInfo[]>()
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const paths = selectionRanges.codeBasedSelections.map(({ range }) =>
 | 
			
		||||
      getNodePathFromSourceRange(kclManager.ast, range)
 | 
			
		||||
    )
 | 
			
		||||
    const nodes = paths.map(
 | 
			
		||||
      (pathToNode) => getNodeFromPath<Value>(kclManager.ast, pathToNode).node
 | 
			
		||||
    )
 | 
			
		||||
    const isAllTooltips = nodes.every(
 | 
			
		||||
      (node) =>
 | 
			
		||||
        node?.type === 'CallExpression' &&
 | 
			
		||||
        toolTips.includes(node.callee.name as any)
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      const theTransforms = getRemoveConstraintsTransforms(
 | 
			
		||||
        selectionRanges,
 | 
			
		||||
        kclManager.ast,
 | 
			
		||||
        'removeConstrainingValues'
 | 
			
		||||
      )
 | 
			
		||||
      setTransformInfos(theTransforms)
 | 
			
		||||
 | 
			
		||||
      const _enableHorz = isAllTooltips && theTransforms.every(Boolean)
 | 
			
		||||
      setEnableHorz(_enableHorz)
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      console.error(e)
 | 
			
		||||
    }
 | 
			
		||||
  }, [guiMode, selectionRanges])
 | 
			
		||||
  if (guiMode.mode !== 'sketch') return null
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <button
 | 
			
		||||
      onClick={() => {
 | 
			
		||||
        if (!transformInfos) return
 | 
			
		||||
        const { modifiedAst, pathToNodeMap } = transformAstSketchLines({
 | 
			
		||||
          ast: kclManager.ast,
 | 
			
		||||
          selectionRanges,
 | 
			
		||||
          transformInfos,
 | 
			
		||||
          programMemory: kclManager.programMemory,
 | 
			
		||||
          referenceSegName: '',
 | 
			
		||||
        })
 | 
			
		||||
        kclManager.updateAst(modifiedAst, true, {
 | 
			
		||||
          callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
 | 
			
		||||
        })
 | 
			
		||||
      }}
 | 
			
		||||
      disabled={!enableHorz}
 | 
			
		||||
      title="Remove Constraining Values"
 | 
			
		||||
    >
 | 
			
		||||
      Remove Constraining Values
 | 
			
		||||
    </button>
 | 
			
		||||
export function removeConstrainingValuesInfo({
 | 
			
		||||
  selectionRanges,
 | 
			
		||||
}: {
 | 
			
		||||
  selectionRanges: Selections
 | 
			
		||||
}) {
 | 
			
		||||
  const paths = selectionRanges.codeBasedSelections.map(({ range }) =>
 | 
			
		||||
    getNodePathFromSourceRange(kclManager.ast, range)
 | 
			
		||||
  )
 | 
			
		||||
  const nodes = paths.map(
 | 
			
		||||
    (pathToNode) => getNodeFromPath<Value>(kclManager.ast, pathToNode).node
 | 
			
		||||
  )
 | 
			
		||||
  const isAllTooltips = nodes.every(
 | 
			
		||||
    (node) =>
 | 
			
		||||
      node?.type === 'CallExpression' &&
 | 
			
		||||
      toolTips.includes(node.callee.name as any)
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  try {
 | 
			
		||||
    const transforms = getRemoveConstraintsTransforms(
 | 
			
		||||
      selectionRanges,
 | 
			
		||||
      kclManager.ast,
 | 
			
		||||
      'removeConstrainingValues'
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    const enabled = isAllTooltips && transforms.every(Boolean)
 | 
			
		||||
    return { enabled, transforms }
 | 
			
		||||
  } catch (e) {
 | 
			
		||||
    console.error(e)
 | 
			
		||||
    return { enabled: false, transforms: [] }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function applyRemoveConstrainingValues({
 | 
			
		||||
  selectionRanges,
 | 
			
		||||
}: {
 | 
			
		||||
  selectionRanges: Selections
 | 
			
		||||
}): {
 | 
			
		||||
  modifiedAst: Program
 | 
			
		||||
  pathToNodeMap: PathToNodeMap
 | 
			
		||||
} {
 | 
			
		||||
  const { transforms } = removeConstrainingValuesInfo({ selectionRanges })
 | 
			
		||||
  return transformAstSketchLines({
 | 
			
		||||
    ast: kclManager.ast,
 | 
			
		||||
    selectionRanges,
 | 
			
		||||
    transformInfos: transforms,
 | 
			
		||||
    programMemory: kclManager.programMemory,
 | 
			
		||||
    referenceSegName: '',
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
@ -1,18 +1,18 @@
 | 
			
		||||
import { useState, useEffect } from 'react'
 | 
			
		||||
import { create } from 'react-modal-promise'
 | 
			
		||||
import { toolTips, useStore } from '../../useStore'
 | 
			
		||||
import { Value } from '../../lang/wasm'
 | 
			
		||||
import { Selections, toolTips } from '../../useStore'
 | 
			
		||||
import { BinaryPart, Program, Value } from '../../lang/wasm'
 | 
			
		||||
import {
 | 
			
		||||
  getNodePathFromSourceRange,
 | 
			
		||||
  getNodeFromPath,
 | 
			
		||||
} from '../../lang/queryAst'
 | 
			
		||||
import {
 | 
			
		||||
  TransformInfo,
 | 
			
		||||
  getTransformInfos,
 | 
			
		||||
  transformAstSketchLines,
 | 
			
		||||
  ConstraintType,
 | 
			
		||||
  PathToNodeMap,
 | 
			
		||||
} from '../../lang/std/sketchcombos'
 | 
			
		||||
import { SetAngleLengthModal } from '../SetAngleLengthModal'
 | 
			
		||||
import {
 | 
			
		||||
  SetAngleLengthModal,
 | 
			
		||||
  createSetAngleLengthModal,
 | 
			
		||||
} from '../SetAngleLengthModal'
 | 
			
		||||
import {
 | 
			
		||||
  createIdentifier,
 | 
			
		||||
  createVariableDeclaration,
 | 
			
		||||
@ -20,128 +20,132 @@ import {
 | 
			
		||||
import { removeDoubleNegatives } from '../AvailableVarsHelpers'
 | 
			
		||||
import { kclManager } from 'lang/KclSinglton'
 | 
			
		||||
 | 
			
		||||
const getModalInfo = create(SetAngleLengthModal as any)
 | 
			
		||||
const getModalInfo = createSetAngleLengthModal(SetAngleLengthModal)
 | 
			
		||||
 | 
			
		||||
type ButtonType = 'xAbs' | 'yAbs' | 'snapToYAxis' | 'snapToXAxis'
 | 
			
		||||
type Constraint = 'xAbs' | 'yAbs' | 'snapToYAxis' | 'snapToXAxis'
 | 
			
		||||
 | 
			
		||||
const buttonLabels: Record<ButtonType, string> = {
 | 
			
		||||
  xAbs: 'Set distance from X Axis',
 | 
			
		||||
  yAbs: 'Set distance from Y Axis',
 | 
			
		||||
  snapToYAxis: 'Snap To Y Axis',
 | 
			
		||||
  snapToXAxis: 'Snap To X Axis',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
export const SetAbsDistance = ({ buttonType }: { buttonType: ButtonType }) => {
 | 
			
		||||
  const { guiMode, selectionRanges, setCursor } = useStore((s) => ({
 | 
			
		||||
    guiMode: s.guiMode,
 | 
			
		||||
    selectionRanges: s.selectionRanges,
 | 
			
		||||
    setCursor: s.setCursor,
 | 
			
		||||
  }))
 | 
			
		||||
  const disType: ConstraintType =
 | 
			
		||||
    buttonType === 'xAbs' || buttonType === 'yAbs'
 | 
			
		||||
      ? buttonType
 | 
			
		||||
      : buttonType === 'snapToYAxis'
 | 
			
		||||
export function absDistanceInfo({
 | 
			
		||||
  selectionRanges,
 | 
			
		||||
  constraint,
 | 
			
		||||
}: {
 | 
			
		||||
  selectionRanges: Selections
 | 
			
		||||
  constraint: Constraint
 | 
			
		||||
}) {
 | 
			
		||||
  const disType =
 | 
			
		||||
    constraint === 'xAbs' || constraint === 'yAbs'
 | 
			
		||||
      ? constraint
 | 
			
		||||
      : constraint === 'snapToYAxis'
 | 
			
		||||
      ? 'xAbs'
 | 
			
		||||
      : 'yAbs'
 | 
			
		||||
  const [enableAngLen, setEnableAngLen] = useState(false)
 | 
			
		||||
  const [transformInfos, setTransformInfos] = useState<TransformInfo[]>()
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const paths = selectionRanges.codeBasedSelections.map(({ range }) =>
 | 
			
		||||
      getNodePathFromSourceRange(kclManager.ast, range)
 | 
			
		||||
    )
 | 
			
		||||
    const nodes = paths.map(
 | 
			
		||||
      (pathToNode) =>
 | 
			
		||||
        getNodeFromPath<Value>(kclManager.ast, pathToNode, 'CallExpression')
 | 
			
		||||
          .node
 | 
			
		||||
    )
 | 
			
		||||
    const isAllTooltips = nodes.every(
 | 
			
		||||
      (node) =>
 | 
			
		||||
        node?.type === 'CallExpression' &&
 | 
			
		||||
        toolTips.includes(node.callee.name as any)
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    const theTransforms = getTransformInfos(
 | 
			
		||||
      selectionRanges,
 | 
			
		||||
      kclManager.ast,
 | 
			
		||||
      disType
 | 
			
		||||
    )
 | 
			
		||||
    setTransformInfos(theTransforms)
 | 
			
		||||
 | 
			
		||||
    const enableY =
 | 
			
		||||
      disType === 'yAbs' &&
 | 
			
		||||
      selectionRanges.otherSelections.length === 1 &&
 | 
			
		||||
      selectionRanges.otherSelections[0] === 'x-axis' // select the x axis to set the distance from it i.e. y
 | 
			
		||||
    const enableX =
 | 
			
		||||
      disType === 'xAbs' &&
 | 
			
		||||
      selectionRanges.otherSelections.length === 1 &&
 | 
			
		||||
      selectionRanges.otherSelections[0] === 'y-axis' // select the y axis to set the distance from it i.e. x
 | 
			
		||||
 | 
			
		||||
    const _enableHorz =
 | 
			
		||||
      isAllTooltips &&
 | 
			
		||||
      theTransforms.every(Boolean) &&
 | 
			
		||||
      selectionRanges.codeBasedSelections.length === 1 &&
 | 
			
		||||
      (enableX || enableY)
 | 
			
		||||
    setEnableAngLen(_enableHorz)
 | 
			
		||||
  }, [guiMode, selectionRanges])
 | 
			
		||||
  if (guiMode.mode !== 'sketch') return null
 | 
			
		||||
 | 
			
		||||
  const isAlign = buttonType === 'snapToYAxis' || buttonType === 'snapToXAxis'
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <button
 | 
			
		||||
      onClick={async () => {
 | 
			
		||||
        if (!transformInfos) return
 | 
			
		||||
        const { valueUsedInTransform } = transformAstSketchLines({
 | 
			
		||||
          ast: JSON.parse(JSON.stringify(kclManager.ast)),
 | 
			
		||||
          selectionRanges: selectionRanges,
 | 
			
		||||
          transformInfos,
 | 
			
		||||
          programMemory: kclManager.programMemory,
 | 
			
		||||
          referenceSegName: '',
 | 
			
		||||
        })
 | 
			
		||||
        try {
 | 
			
		||||
          let forceVal = valueUsedInTransform || 0
 | 
			
		||||
          const { valueNode, variableName, newVariableInsertIndex, sign } =
 | 
			
		||||
            await (!isAlign &&
 | 
			
		||||
              getModalInfo({
 | 
			
		||||
                value: forceVal,
 | 
			
		||||
                valueName: disType === 'yAbs' ? 'yDis' : 'xDis',
 | 
			
		||||
              } as any))
 | 
			
		||||
          let finalValue = isAlign
 | 
			
		||||
            ? createIdentifier('_0')
 | 
			
		||||
            : removeDoubleNegatives(valueNode, sign, variableName)
 | 
			
		||||
 | 
			
		||||
          const { modifiedAst: _modifiedAst, pathToNodeMap } =
 | 
			
		||||
            transformAstSketchLines({
 | 
			
		||||
              ast: JSON.parse(JSON.stringify(kclManager.ast)),
 | 
			
		||||
              selectionRanges: selectionRanges,
 | 
			
		||||
              transformInfos,
 | 
			
		||||
              programMemory: kclManager.programMemory,
 | 
			
		||||
              referenceSegName: '',
 | 
			
		||||
              forceValueUsedInTransform: finalValue,
 | 
			
		||||
            })
 | 
			
		||||
          if (variableName) {
 | 
			
		||||
            const newBody = [..._modifiedAst.body]
 | 
			
		||||
            newBody.splice(
 | 
			
		||||
              newVariableInsertIndex,
 | 
			
		||||
              0,
 | 
			
		||||
              createVariableDeclaration(variableName, valueNode)
 | 
			
		||||
            )
 | 
			
		||||
            _modifiedAst.body = newBody
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          kclManager.updateAst(_modifiedAst, true, {
 | 
			
		||||
            callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
 | 
			
		||||
          })
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
          console.log('error', e)
 | 
			
		||||
        }
 | 
			
		||||
      }}
 | 
			
		||||
      disabled={!enableAngLen}
 | 
			
		||||
      title={buttonLabels[buttonType]}
 | 
			
		||||
    >
 | 
			
		||||
      {buttonLabels[buttonType]}
 | 
			
		||||
    </button>
 | 
			
		||||
  const paths = selectionRanges.codeBasedSelections.map(({ range }) =>
 | 
			
		||||
    getNodePathFromSourceRange(kclManager.ast, range)
 | 
			
		||||
  )
 | 
			
		||||
  const nodes = paths.map(
 | 
			
		||||
    (pathToNode) =>
 | 
			
		||||
      getNodeFromPath<Value>(kclManager.ast, pathToNode, 'CallExpression').node
 | 
			
		||||
  )
 | 
			
		||||
  const isAllTooltips = nodes.every(
 | 
			
		||||
    (node) =>
 | 
			
		||||
      node?.type === 'CallExpression' &&
 | 
			
		||||
      toolTips.includes(node.callee.name as any)
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  const transforms = getTransformInfos(selectionRanges, kclManager.ast, disType)
 | 
			
		||||
 | 
			
		||||
  const enableY =
 | 
			
		||||
    disType === 'yAbs' &&
 | 
			
		||||
    selectionRanges.otherSelections.length === 1 &&
 | 
			
		||||
    selectionRanges.otherSelections[0] === 'x-axis' // select the x axis to set the distance from it i.e. y
 | 
			
		||||
  const enableX =
 | 
			
		||||
    disType === 'xAbs' &&
 | 
			
		||||
    selectionRanges.otherSelections.length === 1 &&
 | 
			
		||||
    selectionRanges.otherSelections[0] === 'y-axis' // select the y axis to set the distance from it i.e. x
 | 
			
		||||
 | 
			
		||||
  const enabled =
 | 
			
		||||
    isAllTooltips &&
 | 
			
		||||
    transforms.every(Boolean) &&
 | 
			
		||||
    selectionRanges.codeBasedSelections.length === 1 &&
 | 
			
		||||
    (enableX || enableY)
 | 
			
		||||
 | 
			
		||||
  return { enabled, transforms }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function applyConstraintAbsDistance({
 | 
			
		||||
  selectionRanges,
 | 
			
		||||
  constraint,
 | 
			
		||||
}: {
 | 
			
		||||
  selectionRanges: Selections
 | 
			
		||||
  constraint: 'xAbs' | 'yAbs'
 | 
			
		||||
}): Promise<{
 | 
			
		||||
  modifiedAst: Program
 | 
			
		||||
  pathToNodeMap: PathToNodeMap
 | 
			
		||||
}> {
 | 
			
		||||
  const transformInfos = absDistanceInfo({
 | 
			
		||||
    selectionRanges,
 | 
			
		||||
    constraint,
 | 
			
		||||
  }).transforms
 | 
			
		||||
  const { valueUsedInTransform } = transformAstSketchLines({
 | 
			
		||||
    ast: JSON.parse(JSON.stringify(kclManager.ast)),
 | 
			
		||||
    selectionRanges: selectionRanges,
 | 
			
		||||
    transformInfos,
 | 
			
		||||
    programMemory: kclManager.programMemory,
 | 
			
		||||
    referenceSegName: '',
 | 
			
		||||
  })
 | 
			
		||||
  let forceVal = valueUsedInTransform || 0
 | 
			
		||||
  const { valueNode, variableName, newVariableInsertIndex, sign } =
 | 
			
		||||
    await getModalInfo({
 | 
			
		||||
      value: forceVal,
 | 
			
		||||
      valueName: constraint === 'yAbs' ? 'yDis' : 'xDis',
 | 
			
		||||
    })
 | 
			
		||||
  let finalValue = removeDoubleNegatives(
 | 
			
		||||
    valueNode as BinaryPart,
 | 
			
		||||
    sign,
 | 
			
		||||
    variableName
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  const { modifiedAst: _modifiedAst, pathToNodeMap } = transformAstSketchLines({
 | 
			
		||||
    ast: JSON.parse(JSON.stringify(kclManager.ast)),
 | 
			
		||||
    selectionRanges: selectionRanges,
 | 
			
		||||
    transformInfos,
 | 
			
		||||
    programMemory: kclManager.programMemory,
 | 
			
		||||
    referenceSegName: '',
 | 
			
		||||
    forceValueUsedInTransform: finalValue,
 | 
			
		||||
  })
 | 
			
		||||
  if (variableName) {
 | 
			
		||||
    const newBody = [..._modifiedAst.body]
 | 
			
		||||
    newBody.splice(
 | 
			
		||||
      newVariableInsertIndex,
 | 
			
		||||
      0,
 | 
			
		||||
      createVariableDeclaration(variableName, valueNode)
 | 
			
		||||
    )
 | 
			
		||||
    _modifiedAst.body = newBody
 | 
			
		||||
  }
 | 
			
		||||
  return { modifiedAst: _modifiedAst, pathToNodeMap }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function applyConstraintAxisAlign({
 | 
			
		||||
  selectionRanges,
 | 
			
		||||
  constraint,
 | 
			
		||||
}: {
 | 
			
		||||
  selectionRanges: Selections
 | 
			
		||||
  constraint: 'snapToYAxis' | 'snapToXAxis'
 | 
			
		||||
}): {
 | 
			
		||||
  modifiedAst: Program
 | 
			
		||||
  pathToNodeMap: PathToNodeMap
 | 
			
		||||
} {
 | 
			
		||||
  const transformInfos = absDistanceInfo({
 | 
			
		||||
    selectionRanges,
 | 
			
		||||
    constraint,
 | 
			
		||||
  }).transforms
 | 
			
		||||
 | 
			
		||||
  let finalValue = createIdentifier('_0')
 | 
			
		||||
 | 
			
		||||
  return transformAstSketchLines({
 | 
			
		||||
    ast: JSON.parse(JSON.stringify(kclManager.ast)),
 | 
			
		||||
    selectionRanges: selectionRanges,
 | 
			
		||||
    transformInfos,
 | 
			
		||||
    programMemory: kclManager.programMemory,
 | 
			
		||||
    referenceSegName: '',
 | 
			
		||||
    forceValueUsedInTransform: finalValue,
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,4 @@
 | 
			
		||||
import { useState, useEffect } from 'react'
 | 
			
		||||
import { create } from 'react-modal-promise'
 | 
			
		||||
import { Selections, toolTips, useStore } from '../../useStore'
 | 
			
		||||
import { Selections, toolTips } from '../../useStore'
 | 
			
		||||
import { BinaryPart, Program, Value, VariableDeclarator } from '../../lang/wasm'
 | 
			
		||||
import {
 | 
			
		||||
  getNodePathFromSourceRange,
 | 
			
		||||
@ -8,107 +6,16 @@ import {
 | 
			
		||||
} from '../../lang/queryAst'
 | 
			
		||||
import { isSketchVariablesLinked } from '../../lang/std/sketchConstraints'
 | 
			
		||||
import {
 | 
			
		||||
  TransformInfo,
 | 
			
		||||
  transformSecondarySketchLinesTagFirst,
 | 
			
		||||
  getTransformInfos,
 | 
			
		||||
  PathToNodeMap,
 | 
			
		||||
} from '../../lang/std/sketchcombos'
 | 
			
		||||
import { GetInfoModal } from '../SetHorVertDistanceModal'
 | 
			
		||||
import { GetInfoModal, createInfoModal } from '../SetHorVertDistanceModal'
 | 
			
		||||
import { createVariableDeclaration } from '../../lang/modifyAst'
 | 
			
		||||
import { removeDoubleNegatives } from '../AvailableVarsHelpers'
 | 
			
		||||
import { kclManager } from 'lang/KclSinglton'
 | 
			
		||||
 | 
			
		||||
const getModalInfo = create(GetInfoModal as any)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
export const SetAngleBetween = () => {
 | 
			
		||||
  const { guiMode, selectionRanges, setCursor } = useStore((s) => ({
 | 
			
		||||
    guiMode: s.guiMode,
 | 
			
		||||
    selectionRanges: s.selectionRanges,
 | 
			
		||||
    setCursor: s.setCursor,
 | 
			
		||||
  }))
 | 
			
		||||
  const [enable, setEnable] = useState(false)
 | 
			
		||||
  const [transformInfos, setTransformInfos] = useState<TransformInfo[]>()
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const { enabled, transforms } = angleBetweenInfo({ selectionRanges })
 | 
			
		||||
    setTransformInfos(transforms)
 | 
			
		||||
    setEnable(enabled)
 | 
			
		||||
  }, [guiMode, selectionRanges])
 | 
			
		||||
  if (guiMode.mode !== 'sketch') return null
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <button
 | 
			
		||||
      onClick={async () => {
 | 
			
		||||
        if (!transformInfos) return
 | 
			
		||||
        const { modifiedAst, tagInfo, valueUsedInTransform, pathToNodeMap } =
 | 
			
		||||
          transformSecondarySketchLinesTagFirst({
 | 
			
		||||
            ast: JSON.parse(JSON.stringify(kclManager.ast)),
 | 
			
		||||
            selectionRanges,
 | 
			
		||||
            transformInfos,
 | 
			
		||||
            programMemory: kclManager.programMemory,
 | 
			
		||||
          })
 | 
			
		||||
        const {
 | 
			
		||||
          segName,
 | 
			
		||||
          value,
 | 
			
		||||
          valueNode,
 | 
			
		||||
          variableName,
 | 
			
		||||
          newVariableInsertIndex,
 | 
			
		||||
          sign,
 | 
			
		||||
        }: {
 | 
			
		||||
          segName: string
 | 
			
		||||
          value: number
 | 
			
		||||
          valueNode: Value
 | 
			
		||||
          variableName?: string
 | 
			
		||||
          newVariableInsertIndex: number
 | 
			
		||||
          sign: number
 | 
			
		||||
        } = await getModalInfo({
 | 
			
		||||
          segName: tagInfo?.tag,
 | 
			
		||||
          isSegNameEditable: !tagInfo?.isTagExisting,
 | 
			
		||||
          value: valueUsedInTransform,
 | 
			
		||||
          initialVariableName: 'angle',
 | 
			
		||||
        } as any)
 | 
			
		||||
        if (segName === tagInfo?.tag && value === valueUsedInTransform) {
 | 
			
		||||
          kclManager.updateAst(modifiedAst, true, {
 | 
			
		||||
            callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
 | 
			
		||||
          })
 | 
			
		||||
        } else {
 | 
			
		||||
          const finalValue = removeDoubleNegatives(
 | 
			
		||||
            valueNode as BinaryPart,
 | 
			
		||||
            sign,
 | 
			
		||||
            variableName
 | 
			
		||||
          )
 | 
			
		||||
          // transform again but forcing certain values
 | 
			
		||||
          const { modifiedAst: _modifiedAst, pathToNodeMap } =
 | 
			
		||||
            transformSecondarySketchLinesTagFirst({
 | 
			
		||||
              ast: kclManager.ast,
 | 
			
		||||
              selectionRanges,
 | 
			
		||||
              transformInfos,
 | 
			
		||||
              programMemory: kclManager.programMemory,
 | 
			
		||||
              forceSegName: segName,
 | 
			
		||||
              forceValueUsedInTransform: finalValue,
 | 
			
		||||
            })
 | 
			
		||||
          if (variableName) {
 | 
			
		||||
            const newBody = [..._modifiedAst.body]
 | 
			
		||||
            newBody.splice(
 | 
			
		||||
              newVariableInsertIndex,
 | 
			
		||||
              0,
 | 
			
		||||
              createVariableDeclaration(variableName, valueNode)
 | 
			
		||||
            )
 | 
			
		||||
            _modifiedAst.body = newBody
 | 
			
		||||
          }
 | 
			
		||||
          kclManager.updateAst(_modifiedAst, true, {
 | 
			
		||||
            callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
 | 
			
		||||
          })
 | 
			
		||||
        }
 | 
			
		||||
      }}
 | 
			
		||||
      disabled={!enable}
 | 
			
		||||
      title="Set Angle Between"
 | 
			
		||||
    >
 | 
			
		||||
      Set Angle Between
 | 
			
		||||
    </button>
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
const getModalInfo = createInfoModal(GetInfoModal)
 | 
			
		||||
 | 
			
		||||
export function angleBetweenInfo({
 | 
			
		||||
  selectionRanges,
 | 
			
		||||
@ -183,28 +90,17 @@ export async function applyConstraintAngleBetween({
 | 
			
		||||
    variableName,
 | 
			
		||||
    newVariableInsertIndex,
 | 
			
		||||
    sign,
 | 
			
		||||
  }: {
 | 
			
		||||
    segName: string
 | 
			
		||||
    value: number
 | 
			
		||||
    valueNode: Value
 | 
			
		||||
    variableName?: string
 | 
			
		||||
    newVariableInsertIndex: number
 | 
			
		||||
    sign: number
 | 
			
		||||
  } = await getModalInfo({
 | 
			
		||||
    segName: tagInfo?.tag,
 | 
			
		||||
    isSegNameEditable: !tagInfo?.isTagExisting,
 | 
			
		||||
    value: valueUsedInTransform,
 | 
			
		||||
    initialVariableName: 'angle',
 | 
			
		||||
  } as any)
 | 
			
		||||
  if (segName === tagInfo?.tag && value === valueUsedInTransform) {
 | 
			
		||||
  if (segName === tagInfo?.tag && Number(value) === valueUsedInTransform) {
 | 
			
		||||
    return {
 | 
			
		||||
      modifiedAst,
 | 
			
		||||
      pathToNodeMap,
 | 
			
		||||
    }
 | 
			
		||||
    // kclManager.updateAst(modifiedAst, true, {
 | 
			
		||||
    // TODO handle cursor
 | 
			
		||||
    //   callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
 | 
			
		||||
    // })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const finalValue = removeDoubleNegatives(
 | 
			
		||||
@ -235,8 +131,4 @@ export async function applyConstraintAngleBetween({
 | 
			
		||||
    modifiedAst: _modifiedAst,
 | 
			
		||||
    pathToNodeMap: _pathToNodeMap,
 | 
			
		||||
  }
 | 
			
		||||
  // kclManager.updateAst(_modifiedAst, true, {
 | 
			
		||||
  // TODO handle cursor
 | 
			
		||||
  //   callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
 | 
			
		||||
  // })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,4 @@
 | 
			
		||||
import { useState, useEffect } from 'react'
 | 
			
		||||
import { create } from 'react-modal-promise'
 | 
			
		||||
import { toolTips, useStore } from '../../useStore'
 | 
			
		||||
import { toolTips } from '../../useStore'
 | 
			
		||||
import { BinaryPart, Program, Value, VariableDeclarator } from '../../lang/wasm'
 | 
			
		||||
import {
 | 
			
		||||
  getNodePathFromSourceRange,
 | 
			
		||||
@ -8,139 +6,17 @@ import {
 | 
			
		||||
} from '../../lang/queryAst'
 | 
			
		||||
import { isSketchVariablesLinked } from '../../lang/std/sketchConstraints'
 | 
			
		||||
import {
 | 
			
		||||
  TransformInfo,
 | 
			
		||||
  transformSecondarySketchLinesTagFirst,
 | 
			
		||||
  getTransformInfos,
 | 
			
		||||
  ConstraintType,
 | 
			
		||||
  PathToNodeMap,
 | 
			
		||||
} from '../../lang/std/sketchcombos'
 | 
			
		||||
import { GetInfoModal } from '../SetHorVertDistanceModal'
 | 
			
		||||
import { GetInfoModal, createInfoModal } from '../SetHorVertDistanceModal'
 | 
			
		||||
import { createLiteral, createVariableDeclaration } from '../../lang/modifyAst'
 | 
			
		||||
import { removeDoubleNegatives } from '../AvailableVarsHelpers'
 | 
			
		||||
import { kclManager } from 'lang/KclSinglton'
 | 
			
		||||
import { Selections } from 'useStore'
 | 
			
		||||
 | 
			
		||||
const getModalInfo = create(GetInfoModal as any)
 | 
			
		||||
 | 
			
		||||
type ButtonType =
 | 
			
		||||
  | 'setHorzDistance'
 | 
			
		||||
  | 'setVertDistance'
 | 
			
		||||
  | 'alignEndsHorizontally'
 | 
			
		||||
  | 'alignEndsVertically'
 | 
			
		||||
 | 
			
		||||
const buttonLabels: Record<ButtonType, string> = {
 | 
			
		||||
  setHorzDistance: 'Set Horizontal Distance',
 | 
			
		||||
  setVertDistance: 'Set Vertical Distance',
 | 
			
		||||
  alignEndsHorizontally: 'Align Ends Horizontally',
 | 
			
		||||
  alignEndsVertically: 'Align Ends Vertically',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
export const SetHorzVertDistance = ({
 | 
			
		||||
  buttonType,
 | 
			
		||||
}: {
 | 
			
		||||
  buttonType: ButtonType
 | 
			
		||||
}) => {
 | 
			
		||||
  const { guiMode, selectionRanges, setCursor } = useStore((s) => ({
 | 
			
		||||
    guiMode: s.guiMode,
 | 
			
		||||
    selectionRanges: s.selectionRanges,
 | 
			
		||||
    setCursor: s.setCursor,
 | 
			
		||||
  }))
 | 
			
		||||
  const constraint: ConstraintType =
 | 
			
		||||
    buttonType === 'setHorzDistance' || buttonType === 'setVertDistance'
 | 
			
		||||
      ? buttonType
 | 
			
		||||
      : buttonType === 'alignEndsHorizontally'
 | 
			
		||||
      ? 'setVertDistance'
 | 
			
		||||
      : 'setHorzDistance'
 | 
			
		||||
  const [enable, setEnable] = useState(false)
 | 
			
		||||
  const [transformInfos, setTransformInfos] = useState<TransformInfo[]>()
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const { transforms, enabled } = horzVertDistanceInfo({
 | 
			
		||||
      selectionRanges,
 | 
			
		||||
      constraint,
 | 
			
		||||
    })
 | 
			
		||||
    setTransformInfos(transforms)
 | 
			
		||||
    setEnable(enabled)
 | 
			
		||||
  }, [guiMode, selectionRanges])
 | 
			
		||||
  if (guiMode.mode !== 'sketch') return null
 | 
			
		||||
 | 
			
		||||
  const isAlign =
 | 
			
		||||
    buttonType === 'alignEndsHorizontally' ||
 | 
			
		||||
    buttonType === 'alignEndsVertically'
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <button
 | 
			
		||||
      onClick={async () => {
 | 
			
		||||
        if (!transformInfos) return
 | 
			
		||||
        const { modifiedAst, tagInfo, valueUsedInTransform, pathToNodeMap } =
 | 
			
		||||
          transformSecondarySketchLinesTagFirst({
 | 
			
		||||
            ast: JSON.parse(JSON.stringify(kclManager.ast)),
 | 
			
		||||
            selectionRanges,
 | 
			
		||||
            transformInfos,
 | 
			
		||||
            programMemory: kclManager.programMemory,
 | 
			
		||||
          })
 | 
			
		||||
        const {
 | 
			
		||||
          segName,
 | 
			
		||||
          value,
 | 
			
		||||
          valueNode,
 | 
			
		||||
          variableName,
 | 
			
		||||
          newVariableInsertIndex,
 | 
			
		||||
          sign,
 | 
			
		||||
        }: {
 | 
			
		||||
          segName: string
 | 
			
		||||
          value: number
 | 
			
		||||
          valueNode: Value
 | 
			
		||||
          variableName?: string
 | 
			
		||||
          newVariableInsertIndex: number
 | 
			
		||||
          sign: number
 | 
			
		||||
        } = await (!isAlign &&
 | 
			
		||||
          getModalInfo({
 | 
			
		||||
            segName: tagInfo?.tag,
 | 
			
		||||
            isSegNameEditable: !tagInfo?.isTagExisting,
 | 
			
		||||
            value: valueUsedInTransform,
 | 
			
		||||
            initialVariableName:
 | 
			
		||||
              constraint === 'setHorzDistance' ? 'xDis' : 'yDis',
 | 
			
		||||
          } as any))
 | 
			
		||||
        if (segName === tagInfo?.tag && value === valueUsedInTransform) {
 | 
			
		||||
          kclManager.updateAst(modifiedAst, true, {
 | 
			
		||||
            callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
 | 
			
		||||
          })
 | 
			
		||||
        } else {
 | 
			
		||||
          let finalValue = isAlign
 | 
			
		||||
            ? createLiteral(0)
 | 
			
		||||
            : removeDoubleNegatives(valueNode as BinaryPart, sign, variableName)
 | 
			
		||||
          // transform again but forcing certain values
 | 
			
		||||
          const { modifiedAst: _modifiedAst, pathToNodeMap } =
 | 
			
		||||
            transformSecondarySketchLinesTagFirst({
 | 
			
		||||
              ast: kclManager.ast,
 | 
			
		||||
              selectionRanges,
 | 
			
		||||
              transformInfos,
 | 
			
		||||
              programMemory: kclManager.programMemory,
 | 
			
		||||
              forceSegName: segName,
 | 
			
		||||
              forceValueUsedInTransform: finalValue,
 | 
			
		||||
            })
 | 
			
		||||
          if (variableName) {
 | 
			
		||||
            const newBody = [..._modifiedAst.body]
 | 
			
		||||
            newBody.splice(
 | 
			
		||||
              newVariableInsertIndex,
 | 
			
		||||
              0,
 | 
			
		||||
              createVariableDeclaration(variableName, valueNode)
 | 
			
		||||
            )
 | 
			
		||||
            _modifiedAst.body = newBody
 | 
			
		||||
          }
 | 
			
		||||
          kclManager.updateAst(_modifiedAst, true, {
 | 
			
		||||
            callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
 | 
			
		||||
          })
 | 
			
		||||
        }
 | 
			
		||||
      }}
 | 
			
		||||
      disabled={!enable}
 | 
			
		||||
      title={buttonLabels[buttonType]}
 | 
			
		||||
    >
 | 
			
		||||
      {buttonLabels[buttonType]}
 | 
			
		||||
    </button>
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
const getModalInfo = createInfoModal(GetInfoModal)
 | 
			
		||||
 | 
			
		||||
export function horzVertDistanceInfo({
 | 
			
		||||
  selectionRanges,
 | 
			
		||||
@ -201,7 +77,7 @@ export async function applyConstraintHorzVertDistance({
 | 
			
		||||
}: {
 | 
			
		||||
  selectionRanges: Selections
 | 
			
		||||
  constraint: 'setHorzDistance' | 'setVertDistance'
 | 
			
		||||
  isAlign?: boolean
 | 
			
		||||
  isAlign?: false
 | 
			
		||||
}): Promise<{
 | 
			
		||||
  modifiedAst: Program
 | 
			
		||||
  pathToNodeMap: PathToNodeMap
 | 
			
		||||
@ -224,29 +100,17 @@ export async function applyConstraintHorzVertDistance({
 | 
			
		||||
    variableName,
 | 
			
		||||
    newVariableInsertIndex,
 | 
			
		||||
    sign,
 | 
			
		||||
  }: {
 | 
			
		||||
    segName: string
 | 
			
		||||
    value: number
 | 
			
		||||
    valueNode: Value
 | 
			
		||||
    variableName?: string
 | 
			
		||||
    newVariableInsertIndex: number
 | 
			
		||||
    sign: number
 | 
			
		||||
  } = await (!isAlign &&
 | 
			
		||||
    getModalInfo({
 | 
			
		||||
      segName: tagInfo?.tag,
 | 
			
		||||
      isSegNameEditable: !tagInfo?.isTagExisting,
 | 
			
		||||
      value: valueUsedInTransform,
 | 
			
		||||
      initialVariableName: constraint === 'setHorzDistance' ? 'xDis' : 'yDis',
 | 
			
		||||
    } as any))
 | 
			
		||||
  if (segName === tagInfo?.tag && value === valueUsedInTransform) {
 | 
			
		||||
  } = await getModalInfo({
 | 
			
		||||
    segName: tagInfo?.tag,
 | 
			
		||||
    isSegNameEditable: !tagInfo?.isTagExisting,
 | 
			
		||||
    value: valueUsedInTransform,
 | 
			
		||||
    initialVariableName: constraint === 'setHorzDistance' ? 'xDis' : 'yDis',
 | 
			
		||||
  } as any)
 | 
			
		||||
  if (segName === tagInfo?.tag && Number(value) === valueUsedInTransform) {
 | 
			
		||||
    return {
 | 
			
		||||
      modifiedAst,
 | 
			
		||||
      pathToNodeMap,
 | 
			
		||||
    }
 | 
			
		||||
    // TODO handle cursor stuff
 | 
			
		||||
    // kclManager.updateAst(modifiedAst, true, {
 | 
			
		||||
    //   callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
 | 
			
		||||
    // })
 | 
			
		||||
  } else {
 | 
			
		||||
    let finalValue = isAlign
 | 
			
		||||
      ? createLiteral(0)
 | 
			
		||||
@ -274,10 +138,6 @@ export async function applyConstraintHorzVertDistance({
 | 
			
		||||
      modifiedAst: _modifiedAst,
 | 
			
		||||
      pathToNodeMap,
 | 
			
		||||
    }
 | 
			
		||||
    // TODO handle cursor stuff
 | 
			
		||||
    // kclManager.updateAst(_modifiedAst, true, {
 | 
			
		||||
    //   callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
 | 
			
		||||
    // })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -307,8 +167,4 @@ export function applyConstraintHorzVertAlign({
 | 
			
		||||
    modifiedAst: modifiedAst,
 | 
			
		||||
    pathToNodeMap,
 | 
			
		||||
  }
 | 
			
		||||
  // TODO handle cursor stuff
 | 
			
		||||
  // kclManager.updateAst(_modifiedAst, true, {
 | 
			
		||||
  //   callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
 | 
			
		||||
  // })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,18 +1,18 @@
 | 
			
		||||
import { useState, useEffect } from 'react'
 | 
			
		||||
import { create } from 'react-modal-promise'
 | 
			
		||||
import { Selections, toolTips, useStore } from '../../useStore'
 | 
			
		||||
import { Program, Value } from '../../lang/wasm'
 | 
			
		||||
import { Selections, toolTips } from '../../useStore'
 | 
			
		||||
import { BinaryPart, Program, Value } from '../../lang/wasm'
 | 
			
		||||
import {
 | 
			
		||||
  getNodePathFromSourceRange,
 | 
			
		||||
  getNodeFromPath,
 | 
			
		||||
} from '../../lang/queryAst'
 | 
			
		||||
import {
 | 
			
		||||
  PathToNodeMap,
 | 
			
		||||
  TransformInfo,
 | 
			
		||||
  getTransformInfos,
 | 
			
		||||
  transformAstSketchLines,
 | 
			
		||||
} from '../../lang/std/sketchcombos'
 | 
			
		||||
import { SetAngleLengthModal } from '../SetAngleLengthModal'
 | 
			
		||||
import {
 | 
			
		||||
  SetAngleLengthModal,
 | 
			
		||||
  createSetAngleLengthModal,
 | 
			
		||||
} from '../SetAngleLengthModal'
 | 
			
		||||
import {
 | 
			
		||||
  createBinaryExpressionWithUnary,
 | 
			
		||||
  createIdentifier,
 | 
			
		||||
@ -22,128 +22,7 @@ import { removeDoubleNegatives } from '../AvailableVarsHelpers'
 | 
			
		||||
import { normaliseAngle } from '../../lib/utils'
 | 
			
		||||
import { kclManager } from 'lang/KclSinglton'
 | 
			
		||||
 | 
			
		||||
const getModalInfo = create(SetAngleLengthModal as any)
 | 
			
		||||
 | 
			
		||||
type ButtonType = 'setAngle' | 'setLength'
 | 
			
		||||
 | 
			
		||||
const buttonLabels: Record<ButtonType, string> = {
 | 
			
		||||
  setAngle: 'Set Angle',
 | 
			
		||||
  setLength: 'Set Length',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
export const SetAngleLength = ({
 | 
			
		||||
  angleOrLength,
 | 
			
		||||
}: {
 | 
			
		||||
  angleOrLength: ButtonType
 | 
			
		||||
}) => {
 | 
			
		||||
  const { guiMode, selectionRanges, setCursor } = useStore((s) => ({
 | 
			
		||||
    guiMode: s.guiMode,
 | 
			
		||||
    selectionRanges: s.selectionRanges,
 | 
			
		||||
    setCursor: s.setCursor,
 | 
			
		||||
  }))
 | 
			
		||||
  const [enableAngLen, setEnableAngLen] = useState(false)
 | 
			
		||||
  const [transformInfos, setTransformInfos] = useState<TransformInfo[]>()
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const { enabled, transforms } = setAngleLengthInfo({
 | 
			
		||||
      selectionRanges,
 | 
			
		||||
      angleOrLength,
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    setTransformInfos(transforms)
 | 
			
		||||
    setEnableAngLen(enabled)
 | 
			
		||||
  }, [guiMode, selectionRanges])
 | 
			
		||||
  if (guiMode.mode !== 'sketch') return null
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <button
 | 
			
		||||
      onClick={async () => {
 | 
			
		||||
        if (!transformInfos) return
 | 
			
		||||
        const { valueUsedInTransform } = transformAstSketchLines({
 | 
			
		||||
          ast: JSON.parse(JSON.stringify(kclManager.ast)),
 | 
			
		||||
          selectionRanges,
 | 
			
		||||
          transformInfos,
 | 
			
		||||
          programMemory: kclManager.programMemory,
 | 
			
		||||
          referenceSegName: '',
 | 
			
		||||
        })
 | 
			
		||||
        try {
 | 
			
		||||
          const isReferencingYAxis =
 | 
			
		||||
            selectionRanges.otherSelections.length === 1 &&
 | 
			
		||||
            selectionRanges.otherSelections[0] === 'y-axis'
 | 
			
		||||
          const isReferencingYAxisAngle =
 | 
			
		||||
            isReferencingYAxis && angleOrLength === 'setAngle'
 | 
			
		||||
 | 
			
		||||
          const isReferencingXAxis =
 | 
			
		||||
            selectionRanges.otherSelections.length === 1 &&
 | 
			
		||||
            selectionRanges.otherSelections[0] === 'x-axis'
 | 
			
		||||
          const isReferencingXAxisAngle =
 | 
			
		||||
            isReferencingXAxis && angleOrLength === 'setAngle'
 | 
			
		||||
 | 
			
		||||
          let forceVal = valueUsedInTransform || 0
 | 
			
		||||
          let calcIdentifier = createIdentifier('_0')
 | 
			
		||||
          if (isReferencingYAxisAngle) {
 | 
			
		||||
            calcIdentifier = createIdentifier(forceVal < 0 ? '_270' : '_90')
 | 
			
		||||
            forceVal = normaliseAngle(forceVal + (forceVal < 0 ? 90 : -90))
 | 
			
		||||
          } else if (isReferencingXAxisAngle) {
 | 
			
		||||
            calcIdentifier = createIdentifier(
 | 
			
		||||
              Math.abs(forceVal) > 90 ? '_180' : '_0'
 | 
			
		||||
            )
 | 
			
		||||
            forceVal =
 | 
			
		||||
              Math.abs(forceVal) > 90
 | 
			
		||||
                ? normaliseAngle(forceVal - 180)
 | 
			
		||||
                : forceVal
 | 
			
		||||
          }
 | 
			
		||||
          const { valueNode, variableName, newVariableInsertIndex, sign } =
 | 
			
		||||
            await getModalInfo({
 | 
			
		||||
              value: forceVal,
 | 
			
		||||
              valueName: angleOrLength === 'setAngle' ? 'angle' : 'length',
 | 
			
		||||
              shouldCreateVariable: true,
 | 
			
		||||
            } as any)
 | 
			
		||||
          let finalValue = removeDoubleNegatives(valueNode, sign, variableName)
 | 
			
		||||
          if (
 | 
			
		||||
            isReferencingYAxisAngle ||
 | 
			
		||||
            (isReferencingXAxisAngle && calcIdentifier.name !== '_0')
 | 
			
		||||
          ) {
 | 
			
		||||
            finalValue = createBinaryExpressionWithUnary([
 | 
			
		||||
              calcIdentifier,
 | 
			
		||||
              finalValue,
 | 
			
		||||
            ])
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          const { modifiedAst: _modifiedAst, pathToNodeMap } =
 | 
			
		||||
            transformAstSketchLines({
 | 
			
		||||
              ast: JSON.parse(JSON.stringify(kclManager.ast)),
 | 
			
		||||
              selectionRanges,
 | 
			
		||||
              transformInfos,
 | 
			
		||||
              programMemory: kclManager.programMemory,
 | 
			
		||||
              referenceSegName: '',
 | 
			
		||||
              forceValueUsedInTransform: finalValue,
 | 
			
		||||
            })
 | 
			
		||||
          if (variableName) {
 | 
			
		||||
            const newBody = [..._modifiedAst.body]
 | 
			
		||||
            newBody.splice(
 | 
			
		||||
              newVariableInsertIndex,
 | 
			
		||||
              0,
 | 
			
		||||
              createVariableDeclaration(variableName, valueNode)
 | 
			
		||||
            )
 | 
			
		||||
            _modifiedAst.body = newBody
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          kclManager.updateAst(_modifiedAst, true, {
 | 
			
		||||
            callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
 | 
			
		||||
          })
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
          console.log('erorr', e)
 | 
			
		||||
        }
 | 
			
		||||
      }}
 | 
			
		||||
      disabled={!enableAngLen}
 | 
			
		||||
      title={buttonLabels[angleOrLength]}
 | 
			
		||||
    >
 | 
			
		||||
      {buttonLabels[angleOrLength]}
 | 
			
		||||
    </button>
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
const getModalInfo = createSetAngleLengthModal(SetAngleLengthModal)
 | 
			
		||||
 | 
			
		||||
export function setAngleLengthInfo({
 | 
			
		||||
  selectionRanges,
 | 
			
		||||
@ -220,8 +99,13 @@ export async function applyConstraintAngleLength({
 | 
			
		||||
        value: forceVal,
 | 
			
		||||
        valueName: angleOrLength === 'setAngle' ? 'angle' : 'length',
 | 
			
		||||
        shouldCreateVariable: true,
 | 
			
		||||
      } as any)
 | 
			
		||||
    let finalValue = removeDoubleNegatives(valueNode, sign, variableName)
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
    let finalValue = removeDoubleNegatives(
 | 
			
		||||
      valueNode as BinaryPart,
 | 
			
		||||
      sign,
 | 
			
		||||
      variableName
 | 
			
		||||
    )
 | 
			
		||||
    if (
 | 
			
		||||
      isReferencingYAxisAngle ||
 | 
			
		||||
      (isReferencingXAxisAngle && calcIdentifier.name !== '_0')
 | 
			
		||||
@ -251,9 +135,6 @@ export async function applyConstraintAngleLength({
 | 
			
		||||
      modifiedAst: _modifiedAst,
 | 
			
		||||
      pathToNodeMap,
 | 
			
		||||
    }
 | 
			
		||||
    // kclManager.updateAst(_modifiedAst, true, {
 | 
			
		||||
    //   callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
 | 
			
		||||
    // })
 | 
			
		||||
  } catch (e) {
 | 
			
		||||
    console.log('erorr', e)
 | 
			
		||||
    throw e
 | 
			
		||||
 | 
			
		||||
@ -1,12 +1,14 @@
 | 
			
		||||
import { SetVarNameModal } from 'components/SetVarNameModal'
 | 
			
		||||
import {
 | 
			
		||||
  SetVarNameModal,
 | 
			
		||||
  createSetVarNameModal,
 | 
			
		||||
} from 'components/SetVarNameModal'
 | 
			
		||||
import { kclManager } from 'lang/KclSinglton'
 | 
			
		||||
import { moveValueIntoNewVariable } from 'lang/modifyAst'
 | 
			
		||||
import { isNodeSafeToReplace } from 'lang/queryAst'
 | 
			
		||||
import { useEffect, useState } from 'react'
 | 
			
		||||
import { create } from 'react-modal-promise'
 | 
			
		||||
import { useModelingContext } from './useModelingContext'
 | 
			
		||||
 | 
			
		||||
const getModalInfo = create(SetVarNameModal as any)
 | 
			
		||||
const getModalInfo = createSetVarNameModal(SetVarNameModal)
 | 
			
		||||
 | 
			
		||||
export function useConvertToVariable() {
 | 
			
		||||
  const { context } = useModelingContext()
 | 
			
		||||
@ -28,7 +30,7 @@ export function useConvertToVariable() {
 | 
			
		||||
    try {
 | 
			
		||||
      const { variableName } = await getModalInfo({
 | 
			
		||||
        valueName: 'var',
 | 
			
		||||
      } as any)
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      const { modifiedAst: _modifiedAst } = moveValueIntoNewVariable(
 | 
			
		||||
        kclManager.ast,
 | 
			
		||||
 | 
			
		||||
@ -29,6 +29,15 @@ import { extrudeSketch } from 'lang/modifyAst'
 | 
			
		||||
import { getNodeFromPath } from '../lang/queryAst'
 | 
			
		||||
import { CallExpression, PipeExpression } from '../lang/wasm'
 | 
			
		||||
import { getConstraintLevelFromSourceRange } from 'lang/std/sketchcombos'
 | 
			
		||||
import {
 | 
			
		||||
  applyConstraintEqualAngle,
 | 
			
		||||
  equalAngleInfo,
 | 
			
		||||
} from 'components/Toolbar/EqualAngle'
 | 
			
		||||
import {
 | 
			
		||||
  applyRemoveConstrainingValues,
 | 
			
		||||
  removeConstrainingValuesInfo,
 | 
			
		||||
} from 'components/Toolbar/RemoveConstrainingValues'
 | 
			
		||||
import { intersectInfo } from 'components/Toolbar/Intersect'
 | 
			
		||||
 | 
			
		||||
export const MODELING_PERSIST_KEY = 'MODELING_PERSIST_KEY'
 | 
			
		||||
 | 
			
		||||
@ -52,7 +61,7 @@ export type SetSelections =
 | 
			
		||||
 | 
			
		||||
export const modelingMachine = createMachine(
 | 
			
		||||
  {
 | 
			
		||||
    /** @xstate-layout N4IgpgJg5mDOIC5QFkD2EwBsCWA7KAxAMICGuAxlgNoAMAuoqAA6qzYAu2qujIAHogDMAVgDsAOmEiAjLMGCAHIIAsAJlHKANCACeiaQDZBEsctGrVATmmiaNQQF8H2tBhz5x2CJjAEAymDsAASwWGDknNy0DEggLGyRPLECCMrCCuL20qrCRpYagvnaegjZBtLiBqLploIGCtZVyk4u6Fh4UJ7evgAicGERQSx47NG88RxcSaApdcKSNKIKi8ppwsrLwsX60oriqgaWBgbKImpWqi0gru0eXj4EfaE+g5AwY7ETibyzx5lLu1sygM61ERV0+ho0mU4gURlOwihlis2SuN3cnXuvX6L2CJD42FgH2YrEm3B+QnM4mqdhoyPUILqBm2CAaFTS5houQUCMczmubQxXQeAVxQ1QI2JcVJ32SiGUXPEhjBtWklgaokMzIhqVUNHEG0WgjVqkEUN2aMFHWFvlF4WCbzAUq+UwpqRoGQ2pwacPW4JKJxhgYU0kWu3Wymklrc1qx-gGeIJRPo4xlrrlqUEqkqdMKOSRNEOLPWGTVhkswlU0O5fNaMbu3XjYoAZiRKM60+SMwqMgY7Go6mbalCWaIjLCjtJ0n36tUFNHbpjGwBRXDsMAAJxCAGtAuQABYdhLpmY7SPiSzAyOXwGFUQs01BtXVEEV9VSZr89Gxldrzc7vdD2kGISWPLtTwQepBGpEN8lDGhVBDLYdTUfVZzvYFQ3MS4vytBsHieBMglbdsU0+Ttpn4Sk0KzBR1EKdING1EozQqYxajyNQ6MOBchTjO1BhITBMCPMlKJSSNoIsEEllQrlhGQko9RhZEDFUL1vWEUMcLrRcbUeHF7SCISRLI0CxLdRR2ROJQwQQ2RmMQENJD1OxjR5aE+1rAV6yXB4wD4dgNwAVwwIIRjANdRNlCDlGRJU6kfapK0vdYWSnBQJEsfJMtODYrM-XS+MbAKgtCsBwr-KLgNTMDxPlawJ0DKtXNkLl0o2NjNULPMPQ2HSfL0vxd3YA9iDIShMGGwDopPKjSg0fUaDURFFoVbJ7x1S9oOSmQcl2CtRF461ptG-dxFOg8AElGwE4JhiiszpTqt1pB9C8NA8plynVFlyn1EMzVfdTrAU46PEu87IZukUiNCKAAFtItGJ6XXA+a3vVD6vV2Y41IQlkzAMakLCnD0K0jK9wc6SGLpG67G0IsUHpRkDnosjM3oUi91SsRYjmUywWRUDJRFEY0PXzdQrGpunALls6YexZ4jPhpHHrZtH6tKHkJHkLJ1AUGpsofQxxBEWpxayCXFFl2noZXABHYLsCYIJ2FQVBTM1ijLK5Njp20wtPMEUc+yVRC4vgpZlqjXDfIVg9E-3JWCGXZ3XaCBHUAANwqj2vdm9HZg9NjpPUZbIykFkKYNTD1nsGycjt+modb1OAmCFWIimIvtbVMwczF4wtXqRyEDHfVsiNwtahyTU46Kk7W+T1PkBIXcQjARHkaCPON04cghL716kKVdYjErEWFEy9LoXZKsQT7I3jWEFv5Ydh5183tXd-3VANzYAAF7cHYMfVGvtOZggyOkewqkjBqQrOlOBlQqjyCrEoacR145DRXp-XwRBuCwCCiQPAQR-6AJAWuISQQICEjARQJ0ECXpQOqJULm+QVArFvjqcsMIDg2UwRsdIhVBpCntu3RshDcDEI3KQ3Ae9NyHxoXQ4hE0mE+xYRBGwlh9QpQOp5awdR0piAqOLLS5g0HmlEd+CGeDJEPGkbI+Rxl8A+BPpzOEKk+wOT6nYHk6VNgGkOLkUJOQ1jvzOqvKRRCSFkJ8Pgdgh5mEc20UbDIN4GjHAKopfQjQLzLAVCIrkdE344PEfYwCqcnFxIURQ4BoCTI6GMjgKAuAPHaKWMTJQCFzBZIOEbdK6kYSRg0EsRCdhLyWEiUnfBxBYlyLIfvZRwlmlCWwG0jpGNljQQVMCKohZzBiHSiIHasg1DIhEFpOEMy25VJiTI2pQQwDOxoQkqASStkpDejYA0voqg5HKFOLQvC0gwK0sOPs1g3K3PEAAGTwBVAAKp7TAacM5u2znnd2qKvlCEUDA8ZCk1TpE8qOJQSouQ9SnMIfIGhYUItwMi1F4gAAKEo1xBAAIIQAwBAAgPKIDiklCkmK80zTAnNg0dIUg1JqFWMWKESoThQkyn6I2UgGWIqCCir2F1t7q2CIKyAAreXCo1rVVJ4rEIVEOJlLyZpCz1EJqaA0Bx1JPx+dJLVTKdUsoCDvTlxr+WEIRkwHw64gjuA0ZasVsxgQSBnsPMFyJcmpBvkqXKozlpWDij65leqA2Gu5byk16cXZuyZQAdxxYXUVc1ZgV32G9MeCEjhHGFm9JU2Uq5yGlTYvCNMV6MoLZgcQV1cAcAIHihA6k1T-CuZqXIVc-r2EyPUMQmokJ2AMPmv1eqJ1TqoDVciWj5qmmypkS5cClAghBSUSsxNCglJSosRYu7ynL3liO-dY6AByqAgjspGLAU1QqWYzoZJYC8G0wSvuRMWdSSoim6N0a-TKsK0DYt1WizuW9cS93rcXIQxwsq1DNAcFQtLFijjSAaOoO7VSZRULCrlVbSHBHqVQsBmBaH0PUZVZsqACAQG4GATwuAc6oF3OIGA7AAC0XHGmYHk3gITkGljzEQsiTUxpgXHHSku2EZpjBuX7NMz9dj5ZsY4+QgBDTqG8dUQwyggnhObg3AA8Q4aSDsCExuBGsnAiKfs9xoSqncDqaI9rQ28xDrS0aEbS86UqgZFVdCcw4Z1isfYxwRRB9sBHyc-xxhbmRNiYk1JmTcn5PLMK+FtTqANO6MkOYeVtE4TGBMY1RCzHTOImfDl2zdWit8bUaVxrBAPNeZ835gBgWasjYa5Fpr0W3TqBa2IdS6kOtGE2iUYFO0b7i2MHCOktQht5bIFAHwZXRNMsq9J8TNXrs+Ai1FzRVqUgbdLKcbKUEpxVkCZWC8HplrLFHh6S7eI3EVUm9Njc3nMC+f8wt4Lr2wDvdW59uNiANvQYvuqdtHqpyBN2Fe2QNhKfGiONDqNkUPn7juxVvAVXnvBfeUkrHzXibqErApDQm7VDpXVBUZaHoTgWHzBsOnnOmfw43J5xHs3UdBYU3L7na2MwbeJttKs+QFSxzTWqPYKrG7yCfkoW5QRcCAZIraIiGBWzBUwPdZHTKZ3ZDipICsb1rw8mBKHFCU4YNQjqEbae5hvK2M6CQXLnB8D4ftFMeMXcEyEZxw2yE5RqS6LHDyY4kZSe8OXdSPsGx1T2svPOSznQDzhG3B0JPPduDTq19o0Z+xl0cgOL0kxak-mrHNAxyMst6-kEb4n7uiRp0nvMrj0olNKjGgrhodUwIhagqkOwqj2VTRg4GjH5O4gsOjpP7nOHk72Bt8z8RhAFt9Ti2ktPXR0JkF-EODOBUxo-sDoTrTU-X9c-bFPAI9OfdmBfEWeYXYAeSxNkBDXhbIAnPIQoaECmGWWvY-QAnDYAy-I9VQW-bWEQDNfpYwdSRuewO+FrMebdEMGAvkfkW3DAeAWIGPWNLPe-OkSQGQOQRQFQdQe9RAeTOLFUOoGwTUb-EMWWLEdgu-YEbMKQXRKoQ4TUeEIPA7QcCOXROkN6EMU4aPQdZOWQ-uQ4bMHNVaPZKEdQFkZyJLU7WQMEIweQWFfBYw16S5fYJkMPeQQoKoGuPULvKQHwkMKPP-XBb9bVHDNw7XA4EwS5WlaoLMCwQQ2dM0SoHtfaI4ZQm+PdHAnoMTaIiCYwNI3IJ-EMVVBkRDaCZ9f6WlKwK3TA2mH9HA4DINUtCAQo89NDc2ThXKHwk4fbRASsIMFDG+EEdYCwXI-1A1XeYNToxtcOODCmfZIcRDEYrkSvcY84KYg9K-eYvHV+H3U0BIqQKXFI65fYC9FQFQU4OkD9JeKzKJZollADIDDldgFg+fDgg4SVU4H6U0aeOENYyoFDOkLIRiTDC-X9fY+-YwLKQFMwBNMQmuNIy8HxOKc7QsOnJTRzMbFzS-ITGEi9JaGwARDBWlTfA7Q4PRXIXrUJKEEEOnJbYrcbVzRrIk7-akQcKEHNbIZaExDYTwrSQ4RKKweoOnDHNzDk35PUJwsEhEJQQJRYTIEWBEewOoCsWXBnJJKU09L7PHIvD6d8dBCFXIEXEQTINtZKaoPUQ-QwyGG3O3NsMAGEo4UWEQVVawCsQsYXFCZUwoHkO4tqKsWWOPDjJvafOaLWN0XKC8A5JLG1UokxTKHmJYAofKPQsffcBvCM9PdGaMzmKXSQE4UXQ2OKQoZM7MWQCxREFVOiSE7DFlQA0A9gGE-guLBEpicWcod-EZYEHQynEGe4sRL9KJbApsqEqtDgf+YKYIDcTHAKcIWcl0vUyA6oFScg8oDBG09Q7PPsmcLSRCWwcUxoleccvVQAqcnUxc8gZctsl8BYJYBoR8Y0QY0oDac2A6BUD1cogw--M8qEnA14rFFcr4u-YwMQK9WlBoIGaEX0g7XQ+jWccoQoHtJwJwIAA */
 | 
			
		||||
    /** @xstate-layout N4IgpgJg5mDOIC5QFkD2EwBsCWA7KAxAMICGuAxlgNoAMAuoqAA6qzYAu2qujIAHogDMAVgDsAOmEiAjLMGCAHIIAsAJlHKANCACeiaQDZBEsctGrVATmmiaNQQF8H2tBhz5x2CJjAEAymDsAASwWGDknNy0DEggLGyRPLECCMrCCuL20qrCRpYagvnaegjZBtLiBqLploIGCtZVyk4u6Fh4UJ7evgAicGERQSx47NG88RxcSaApdcKSNKIKi8ppwsrLwsX60oriqgaWBgbKImpWqi0gru0eXj4EfaE+g5AwY7ETibyzx5lLu1sygM61ERV0+ho0mU4gURlOwihlis2SuN3cnXuvX6L2CJD42FgH2YrEm3B+QnM4mqdhoyPUILqBm2CAaFTS5houQUCMczmubQxXQeAVxQ1QI2JcVJ32SiGUXPEhjBtWklgaokMzIhqVUNHEG0WgjVqkEUN2aMFHWFvlF4WCbzAUq+UwpqRoGQ2pwacPW4JKJxhgYU0kWu3Wymklrc1qx-gGeIJRPo4xlrrlqUEqkqdMKOSRNEOLPWGTVhkswlU0O5fNaMbu3XjYoAZiRKM60+SMwqMgY7Go6mbalCWaIjLCjtJ0n36tUFNHbpjGwBRXDsMAAJxCAGtAuQABYdhLpmY7SPiSzAyOXwGFUQs01BtXVEEV9VSZr89Gxldrzc7vdD2kGISWPLtTwQepBGpEN8lDGhVBDLYdTUfVZzvYFQ3MS4vytBsHieBMglbdsU0+Ttpn4Sk0KzBR1EKdING1EozQqYxajyNQ6MOBchTjO1BhITBMCPMlKJSSNoIsEEllQrlhGQko9RhZEDFUL1vWEUMcLrRcbUeHF7SCISRLI0CxLdRR2ROJQwQQ2RmMQENJD1OxjR5aE+1rAV6yXB4wD4dgNwAVwwIIRjANdRNlCDlGRJU6kfapK0vdYWSnBQJEsfJMtODYrM-XS+MbAKgtCsBwr-KLgNTMDxPlawJ0DKtXNkLl0o2NjNULPMPQ2HSfL0vxd3YA9iDIShMGGwDopPKjSg0fUaDURFFoVbJ7x1S9oOSmQcl2CtRF461ptG-dxFOg8AElGwE4JhiiszpTqt1pB9C8NA8plynVFlyn1EMzVfdTrAU46PEu87IZukUiNCKAAFtItGJ6XXA+a3vVD6vV2Y41IQlkzAMakLCnD0K0jK9wc6SGLpG67G0IsUHpRkDnosjM3oUi91SsRYjmUywWRUDJRFEY0PXzdQrGpunALls6YexZ4jPhpHHrZtH6tKHkJHkLJ1AUGpsofQxxBEWpxayCXFFl2noZXABHYLsCYIJ2FQVBTM1ijLK5Njp20wtPMEUc+yVRC4vgpZlqjXDfIVg9E-3JWCGXZ3XaCBHUAANwqj2vdm9HZg9NjpPUZbIykFkKYNTD1nsGycjt+modb1OAmCFWIimIvtbVMwczF4wtXqRyEDHfVsiNwtahyTU46Kk7W+T1PkBIXcQjARHkaCPON04cghL716kKVdYjErEWFEy9LoXZKsQT7I3jWEFv5Ydh5183tXd-3VANzYAAF7cHYMfVGvtOZggyOkewqkjBqQrOlOBlQqjyCrEoacR145DRXp-XwRBuCwCCiQPAQR-6AJAWuISQQICEjARQJ0ECXpQOqJIawHl0hMizOlfI8xsrqTBHZD084cFCntu3RshDcDEI3KQ3Ae9NyHxoXQ4hE0mE+xYRBGwlh9SIlNEoRQvMFDpRfgacohhIyS0jO-M6q8pFEJIWQsgUAfAn05nCFS8g6j2AOPSIWOo9SZSVBWBSthMpiykLYpO+DiCOLkWQnw+B2CHmYRzbRRsMig2hCI0MwhLymyxrYPI5g5zZEKoNcReDJEPGkbI+RQxNxMEinQ8gwVMAkC3KohhpFNHpIxjSTIGweRV0LMtRSiBTSXkqNyMW8kBzRLboBVOdSnEKIocA0BJkdDGRwFAXA7jtFLGJkoBC5gGhqXqBM0o6kYSRg0EsRCdhLyWEWfY2p8SGn72UcJHZQlsD7MORjZY0EFTAiqIWcwYh0oiB2rINQyIRBaThG82JqyEkKLAM7GhSSoApKBSkN6NgDS+iqDkCxaUdTVhgVpYcfZrBuVRTUghnyyFME6SZagaSYrAsRDzVYZZVjqACSULU8wpxmGROsLMhQDBMuWQ4mRayggbjANnPOQRyCsrXMmPpPLCVi2zOkNQ3oRBIhMVShSlgEpG0RO+coYs3kABk8AVQACqe0wGnDObt1X509QSoQigYGPIUmqdInlRxKCVFyHqU58liwqd+CGK8XW4HdZ68QAAFCUa4ggAEEIAYAgAQQtEBxSSm5XNEuwJzYNHSFINSJqtA6kRBUSxUJMp+ltd5ZNNNU2uqCB6r2F1t7q2CGWyApai0Vo1rVfpsxEIVEOJlLyZpCz1EJqaA0Bx1JPyJdJZ1g7h2YFHTvPNk6S2EIRkwHw64gjuA0fO-VQhgQSBnsPNIDQciExvkqXK9zlpWDike9NQ7M0BHPROotU704uzdumgA7u7ANVbi5CArvsN6Y8EJHCOMLN6ISbxaV2PWpNeF+3yzTRmkdV1cAcAIIGhA6k1T-CRZqXIVc-r2EyFcsWRLESFlAzR09dGGNUBquRLR80pnWrpKaOBSgQQtpKJWYmhQuRGz5rYMcwnwMjoAHKoCCDmkYsBp3lpZkxhk1rrDqDBCleTxZ1JKgVPkukWRGJvLQBqk98Yu4Jl7mh7WTIsq1DNAcFQ7nNolA0PMU4fZZ7uXFuRhOtMfMifEBlyq4nguWXc9SLMBxp66OhMgv4hwZwKmNKcS83nc6Zey3gcTknzIvoQCLcVxpLzmHqNYZEd8rCSDyIUaEFMZZiOXvLbLJ6ssNZy+wRjqg9XVqEOkDIFzTTmGq15O+ujKhwiQqXXYFpJspvlvmxDpDggbKoWAzAtD6HqMqs2VABAIDcDAJ4XAOdUC7nEDAdgABaW7WzMBA7wK96zdF+FvkpjfTkMX9DZWtUsdUCFBOmkMG8y713yEAM2dQh73TnuQ7e5uDcADxC3pIOwV7G4EYA8CCDgnd2hIQ9wFDvLGZEIHFQYUU4dJqt1F4eUD61QwRQXFscHHV2OCKIPtgI+xOnuMJe29j76bvu-f+4DoH3ylfs7J9D+QB2UtVinBxUx44QwWBqycaE4tZd44N8rx7ai1dk4IBTqnNO6cAMZ3r13RvOeoBNzCJFfNkRfpF1Sui2ZtIRs1KpW2Z3KN2Nx-LlxPh1fvc+9rv7X29fZ7ABzrnK30PMaUBtxExxbAekONcqsdRYRNGWBseopxe0UeTuITPeJ8A569z7jc1OOn+4Z0z4HJey9h+5xBSO+ochzHVJVkQ489T5EyIiP0Eb9Hd7SyvfvD7Ip4v3LnzXX28A66L8z3FKTZ8m+JuqE0+SLCXg3wceYtIrDHFUhE53eXe-c-YfDcSnUfP3enQPO-U-B-Y3efGTWySoOKG+bKGwKsaFQJCwI1bKYEG+SFLSAaPtXvY-ZpDcZpXAVpdpTpd3HpCqL3S-AvXXZnMgigqgjpDcIHEnRhR-BAlIQ2GEVaI2IwTUNQDfNzc2PqNIYcNtQA+6JpFpJXagrpVXSgXPEfMfWnKAqfIHVgxQtpDgrg1Q0veAivbWAQhYJYXIEeMQh8EQPWKQ-JM0WQtPZOIIXAYzEiW0IiDAVsdpe6DpdNJjcpa1fJZFa8EZIwQmKcC8UMXGI2aecwA-PSEgOXTgfALeXEKYfzTI+0ILMw16YOakXRMcHkY4SMKcdKTjakPsDYdUVdS8URJeDwA8cIbcDoXInubgRjPg-Qe5fYTjDkA4M5KotSElVYc0HxGxVw1o8gdojI7uRIRjVrdmdre+IMY0CuDQdUYEEVPoqQSoXYaQxFD0BCJwfkDwjAeAWIPtZ9VbDrOkSQGQOQRQFQdQFTRAIHfhaBHkfJI2RHbBZovyMAO4yvYEI1DTKoQ4TUeEUOKlQcCOXROkN6EMLvRZUE-uQ4bMIDVaMFKEdQFkZyI2WoQGYk8seVRWboDE16RFfYJkKEbxWVJHBAZEJfBSRkkMJI1LXBKjY9T1aknnA4EwRFBNKQbAj45jM0SoXA+QJEiwJIvTWbHoT7AUiCYwKU3IcWJdTtBkZzaCSEvJZEdUZIqpXksDWbUzC9GDCAVUmTXRfU-IRQAoeQE4ZkysIMNzeokEdYCwRUiDMdXeS9W0xdcOBzCmcFIcZzD0rkL0hSc4P02jejdgYMyZV+dhU0UUordSYsQjO3WoPKQXI4BM09IzEzXNdga4tre4g4WtBLE0TYm+ced05AmMjzV+TKerXzfkqTBdINMWC8clMwN9OoaQGuIbD-TTasHKJoypKbOxGbTNJrJMlMjrFaAczjJiaXUcqlQsO5YEZE2QEIuVVw9LebWbbLRDDgf+YKYIVVIHAKcIG8kEns9rYwdYAchUcoDBaoU0crPcmcQgzKQsGc4g08rskdC8q8oIB8tpdcFct84mIQ79FQY0Zk2QdQc2A6BUPdEMewTszLUsv1eCiXTIN8BoIGaEVQO+P9BLVdA6XAuQ-HShMHWg0nUPFcgxWzXRLSZacoLSWPUVfIbMXnJ5H-TCRi4PFXD3NQsnDi6rakOkdYSsGeEQUxccixPsIRNTbk00jPNI4yQfeg9il86s-onRMQLSMwaWC1JSERGoj0FQEk-JV5E8o-fS4A9XOS2QC8KQOkF8EMbcpSR+EmC5WwUMU4IgnvWmUghQygpQjg1iz3YyqsyvLbDIFQWoqEKQHTOwsXJ+avDvfjHSucg8dwzwtsZ8lK7WI4UWM1TGcNQsKilCRYc2HYukCxeyWWVI67DoxYuaLWN0XKC8CFYkpdTUqo4JbKJYAofKVE2WWY+YqATonlAazmbA4bFAjaHkWoPY0odIBPKcGwWvHsHCJwIAA */
 | 
			
		||||
    id: 'Modeling',
 | 
			
		||||
 | 
			
		||||
    tsTypes: {} as import('./modelingMachine.typegen').Typegen0,
 | 
			
		||||
@ -122,10 +131,13 @@ export const modelingMachine = createMachine(
 | 
			
		||||
        | { type: 'Constrain horizontal distance' }
 | 
			
		||||
        | { type: 'Constrain vertical distance' }
 | 
			
		||||
        | { type: 'Constrain angle' }
 | 
			
		||||
        | { type: 'Constrain perpendicular distance' }
 | 
			
		||||
        | { type: 'Constrain horizontally align' }
 | 
			
		||||
        | { type: 'Constrain vertically align' }
 | 
			
		||||
        | { type: 'Constrain length' }
 | 
			
		||||
        | { type: 'Constrain equal length' }
 | 
			
		||||
        | { type: 'Constrain parallel' }
 | 
			
		||||
        | { type: 'Constrain remove constraints' }
 | 
			
		||||
        | { type: 'extrude intent' },
 | 
			
		||||
      // ,
 | 
			
		||||
    },
 | 
			
		||||
@ -356,6 +368,11 @@ export const modelingMachine = createMachine(
 | 
			
		||||
                cond: 'Can constrain length',
 | 
			
		||||
              },
 | 
			
		||||
 | 
			
		||||
              'Constrain perpendicular distance': {
 | 
			
		||||
                target: 'Await perpendicular distance info',
 | 
			
		||||
                cond: 'Can constrain perpendicular distance',
 | 
			
		||||
              },
 | 
			
		||||
 | 
			
		||||
              'Constrain horizontally align': {
 | 
			
		||||
                cond: 'Can constrain horizontally align',
 | 
			
		||||
                target: 'SketchIdle',
 | 
			
		||||
@ -376,6 +393,20 @@ export const modelingMachine = createMachine(
 | 
			
		||||
                internal: true,
 | 
			
		||||
                actions: ['Constrain equal length'],
 | 
			
		||||
              },
 | 
			
		||||
 | 
			
		||||
              'Constrain parallel': {
 | 
			
		||||
                target: 'SketchIdle',
 | 
			
		||||
                internal: true,
 | 
			
		||||
                cond: 'Can canstrain parallel',
 | 
			
		||||
                actions: ['Constrain parallel'],
 | 
			
		||||
              },
 | 
			
		||||
 | 
			
		||||
              'Constrain remove constraints': {
 | 
			
		||||
                target: 'SketchIdle',
 | 
			
		||||
                internal: true,
 | 
			
		||||
                cond: 'Can constrain remove constraints',
 | 
			
		||||
                actions: ['Constrain remove constraints'],
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            entry: 'equip select',
 | 
			
		||||
@ -528,6 +559,18 @@ export const modelingMachine = createMachine(
 | 
			
		||||
              onError: 'SketchIdle',
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
 | 
			
		||||
          'Await perpendicular distance info': {
 | 
			
		||||
            invoke: {
 | 
			
		||||
              src: 'Get perpendicular distance info',
 | 
			
		||||
              id: 'get-perpendicular-distance-info',
 | 
			
		||||
              onDone: {
 | 
			
		||||
                target: 'SketchIdle',
 | 
			
		||||
                actions: 'Set selection',
 | 
			
		||||
              },
 | 
			
		||||
              onError: 'SketchIdle',
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        initial: 'SketchIdle',
 | 
			
		||||
@ -613,6 +656,8 @@ export const modelingMachine = createMachine(
 | 
			
		||||
        angleBetweenInfo({ selectionRanges }).enabled,
 | 
			
		||||
      'Can constrain length': ({ selectionRanges }) =>
 | 
			
		||||
        setAngleLengthInfo({ selectionRanges }).enabled,
 | 
			
		||||
      'Can constrain perpendicular distance': ({ selectionRanges }) =>
 | 
			
		||||
        intersectInfo({ selectionRanges }).enabled,
 | 
			
		||||
      'Can constrain horizontally align': ({ selectionRanges }) =>
 | 
			
		||||
        horzVertDistanceInfo({ selectionRanges, constraint: 'setHorzDistance' })
 | 
			
		||||
          .enabled,
 | 
			
		||||
@ -621,6 +666,10 @@ export const modelingMachine = createMachine(
 | 
			
		||||
          .enabled,
 | 
			
		||||
      'Can constrain equal length': ({ selectionRanges }) =>
 | 
			
		||||
        setEqualLengthInfo({ selectionRanges }).enabled,
 | 
			
		||||
      'Can canstrain parallel': ({ selectionRanges }) =>
 | 
			
		||||
        equalAngleInfo({ selectionRanges }).enabled,
 | 
			
		||||
      'Can constrain remove constraints': ({ selectionRanges }) =>
 | 
			
		||||
        removeConstrainingValuesInfo({ selectionRanges }).enabled,
 | 
			
		||||
      'has no selection': ({ selectionRanges }) => {
 | 
			
		||||
        if (selectionRanges?.codeBasedSelections?.length < 1) return true
 | 
			
		||||
        const selection = selectionRanges?.codeBasedSelections?.[0] || {}
 | 
			
		||||
@ -825,6 +874,8 @@ export const modelingMachine = createMachine(
 | 
			
		||||
            tool: 'move',
 | 
			
		||||
          },
 | 
			
		||||
        }),
 | 
			
		||||
      // TODO implement source ranges for all of these constraints
 | 
			
		||||
      // need to make the async like the modal constraints
 | 
			
		||||
      'Make selection horizontal': ({ selectionRanges }) => {
 | 
			
		||||
        const { modifiedAst, pathToNodeMap } = applyConstraintHorzVert(
 | 
			
		||||
          selectionRanges,
 | 
			
		||||
@ -832,10 +883,7 @@ export const modelingMachine = createMachine(
 | 
			
		||||
          kclManager.ast,
 | 
			
		||||
          kclManager.programMemory
 | 
			
		||||
        )
 | 
			
		||||
        kclManager.updateAst(modifiedAst, true, {
 | 
			
		||||
          // TODO re implement cursor shit
 | 
			
		||||
          // callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
 | 
			
		||||
        })
 | 
			
		||||
        kclManager.updateAst(modifiedAst, true)
 | 
			
		||||
      },
 | 
			
		||||
      'Make selection vertical': ({ selectionRanges }) => {
 | 
			
		||||
        const { modifiedAst, pathToNodeMap } = applyConstraintHorzVert(
 | 
			
		||||
@ -844,39 +892,39 @@ export const modelingMachine = createMachine(
 | 
			
		||||
          kclManager.ast,
 | 
			
		||||
          kclManager.programMemory
 | 
			
		||||
        )
 | 
			
		||||
        kclManager.updateAst(modifiedAst, true, {
 | 
			
		||||
          // TODO re implement cursor shit
 | 
			
		||||
          // callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
 | 
			
		||||
        })
 | 
			
		||||
        kclManager.updateAst(modifiedAst, true)
 | 
			
		||||
      },
 | 
			
		||||
      'Constrain horizontally align': ({ selectionRanges }) => {
 | 
			
		||||
        const { modifiedAst, pathToNodeMap } = applyConstraintHorzVertAlign({
 | 
			
		||||
          selectionRanges,
 | 
			
		||||
          constraint: 'setVertDistance',
 | 
			
		||||
        })
 | 
			
		||||
        kclManager.updateAst(modifiedAst, true, {
 | 
			
		||||
          // TODO re implement cursor shit
 | 
			
		||||
          // callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
 | 
			
		||||
        })
 | 
			
		||||
        kclManager.updateAst(modifiedAst, true)
 | 
			
		||||
      },
 | 
			
		||||
      'Constrain vertically align': ({ selectionRanges }) => {
 | 
			
		||||
        const { modifiedAst, pathToNodeMap } = applyConstraintHorzVertAlign({
 | 
			
		||||
          selectionRanges,
 | 
			
		||||
          constraint: 'setHorzDistance',
 | 
			
		||||
        })
 | 
			
		||||
        kclManager.updateAst(modifiedAst, true, {
 | 
			
		||||
          // TODO re implement cursor shit
 | 
			
		||||
          // callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
 | 
			
		||||
        })
 | 
			
		||||
        kclManager.updateAst(modifiedAst, true)
 | 
			
		||||
      },
 | 
			
		||||
      'Constrain equal length': ({ selectionRanges }) => {
 | 
			
		||||
        const { modifiedAst, pathToNodeMap } = applyConstraintEqualLength({
 | 
			
		||||
          selectionRanges,
 | 
			
		||||
        })
 | 
			
		||||
        kclManager.updateAst(modifiedAst, true, {
 | 
			
		||||
          // TODO re implement cursor shit
 | 
			
		||||
          // callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
 | 
			
		||||
        kclManager.updateAst(modifiedAst, true)
 | 
			
		||||
      },
 | 
			
		||||
      'Constrain parallel': ({ selectionRanges }) => {
 | 
			
		||||
        const { modifiedAst, pathToNodeMap } = applyConstraintEqualAngle({
 | 
			
		||||
          selectionRanges,
 | 
			
		||||
        })
 | 
			
		||||
        kclManager.updateAst(modifiedAst, true)
 | 
			
		||||
      },
 | 
			
		||||
      'Constrain remove constraints': ({ selectionRanges }) => {
 | 
			
		||||
        const { modifiedAst, pathToNodeMap } = applyRemoveConstrainingValues({
 | 
			
		||||
          selectionRanges,
 | 
			
		||||
        })
 | 
			
		||||
        kclManager.updateAst(modifiedAst, true)
 | 
			
		||||
      },
 | 
			
		||||
      'AST extrude': ({ selectionRanges }) => {
 | 
			
		||||
        const pathToNode = getNodePathFromSourceRange(
 | 
			
		||||
 | 
			
		||||
@ -8,10 +8,12 @@
 | 
			
		||||
"done.invoke.get-angle-info": { type: "done.invoke.get-angle-info"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
 | 
			
		||||
"done.invoke.get-horizontal-info": { type: "done.invoke.get-horizontal-info"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
 | 
			
		||||
"done.invoke.get-length-info": { type: "done.invoke.get-length-info"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
 | 
			
		||||
"done.invoke.get-perpendicular-distance-info": { type: "done.invoke.get-perpendicular-distance-info"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
 | 
			
		||||
"done.invoke.get-vertical-info": { type: "done.invoke.get-vertical-info"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
 | 
			
		||||
"error.platform.get-angle-info": { type: "error.platform.get-angle-info"; data: unknown };
 | 
			
		||||
"error.platform.get-horizontal-info": { type: "error.platform.get-horizontal-info"; data: unknown };
 | 
			
		||||
"error.platform.get-length-info": { type: "error.platform.get-length-info"; data: unknown };
 | 
			
		||||
"error.platform.get-perpendicular-distance-info": { type: "error.platform.get-perpendicular-distance-info"; data: unknown };
 | 
			
		||||
"error.platform.get-vertical-info": { type: "error.platform.get-vertical-info"; data: unknown };
 | 
			
		||||
"xstate.init": { type: "xstate.init" };
 | 
			
		||||
"xstate.stop": { type: "xstate.stop" };
 | 
			
		||||
@ -20,13 +22,14 @@
 | 
			
		||||
          "Get angle info": "done.invoke.get-angle-info";
 | 
			
		||||
"Get horizontal info": "done.invoke.get-horizontal-info";
 | 
			
		||||
"Get length info": "done.invoke.get-length-info";
 | 
			
		||||
"Get perpendicular distance info": "done.invoke.get-perpendicular-distance-info";
 | 
			
		||||
"Get vertical info": "done.invoke.get-vertical-info";
 | 
			
		||||
        };
 | 
			
		||||
        missingImplementations: {
 | 
			
		||||
          actions: "AST add line segment" | "AST start new sketch" | "Modify AST" | "Set selection" | "Update code selection cursors" | "create path" | "set tool" | "show default planes" | "sketch exit execute" | "toast extrude failed";
 | 
			
		||||
          delays: never;
 | 
			
		||||
          guards: "Selection contains axis" | "Selection contains edge" | "Selection contains face" | "Selection contains line" | "Selection contains point" | "Selection is not empty" | "Selection is one face";
 | 
			
		||||
          services: "Get angle info" | "Get horizontal info" | "Get length info" | "Get vertical info";
 | 
			
		||||
          services: "Get angle info" | "Get horizontal info" | "Get length info" | "Get perpendicular distance info" | "Get vertical info";
 | 
			
		||||
        };
 | 
			
		||||
        eventsCausingActions: {
 | 
			
		||||
          "AST add line segment": "Add point";
 | 
			
		||||
@ -37,19 +40,21 @@
 | 
			
		||||
"Clear selection": "Deselect all";
 | 
			
		||||
"Constrain equal length": "Constrain equal length";
 | 
			
		||||
"Constrain horizontally align": "Constrain horizontally align";
 | 
			
		||||
"Constrain parallel": "Constrain parallel";
 | 
			
		||||
"Constrain remove constraints": "Constrain remove constraints";
 | 
			
		||||
"Constrain vertically align": "Constrain vertically align";
 | 
			
		||||
"Make selection horizontal": "Make segment horizontal";
 | 
			
		||||
"Make selection vertical": "Make segment vertical";
 | 
			
		||||
"Modify AST": "Complete line";
 | 
			
		||||
"Remove from code-based selection": "Deselect edge" | "Deselect face" | "Deselect point";
 | 
			
		||||
"Remove from other selection": "Deselect axis";
 | 
			
		||||
"Set selection": "Set selection" | "done.invoke.get-angle-info" | "done.invoke.get-horizontal-info" | "done.invoke.get-length-info" | "done.invoke.get-vertical-info";
 | 
			
		||||
"Set selection": "Set selection" | "done.invoke.get-angle-info" | "done.invoke.get-horizontal-info" | "done.invoke.get-length-info" | "done.invoke.get-perpendicular-distance-info" | "done.invoke.get-vertical-info";
 | 
			
		||||
"Update code selection cursors": "Complete line" | "Deselect all" | "Deselect axis" | "Deselect edge" | "Deselect face" | "Deselect point" | "Deselect segment" | "Select edge" | "Select face" | "Select point" | "Select segment";
 | 
			
		||||
"create path": "Select default plane";
 | 
			
		||||
"default_camera_disable_sketch_mode": "Cancel";
 | 
			
		||||
"edit mode enter": "Enter sketch";
 | 
			
		||||
"edit_mode_exit": "Cancel";
 | 
			
		||||
"equip select": "CancelSketch" | "Constrain equal length" | "Constrain horizontally align" | "Constrain vertically align" | "Deselect point" | "Deselect segment" | "Enter sketch" | "Make segment horizontal" | "Make segment vertical" | "Select default plane" | "Select point" | "Select segment" | "Set selection" | "done.invoke.get-angle-info" | "done.invoke.get-horizontal-info" | "done.invoke.get-length-info" | "done.invoke.get-vertical-info" | "error.platform.get-angle-info" | "error.platform.get-horizontal-info" | "error.platform.get-length-info" | "error.platform.get-vertical-info";
 | 
			
		||||
"equip select": "CancelSketch" | "Constrain equal length" | "Constrain horizontally align" | "Constrain parallel" | "Constrain remove constraints" | "Constrain vertically align" | "Deselect point" | "Deselect segment" | "Enter sketch" | "Make segment horizontal" | "Make segment vertical" | "Select default plane" | "Select point" | "Select segment" | "Set selection" | "done.invoke.get-angle-info" | "done.invoke.get-horizontal-info" | "done.invoke.get-length-info" | "done.invoke.get-perpendicular-distance-info" | "done.invoke.get-vertical-info" | "error.platform.get-angle-info" | "error.platform.get-horizontal-info" | "error.platform.get-length-info" | "error.platform.get-perpendicular-distance-info" | "error.platform.get-vertical-info";
 | 
			
		||||
"hide default planes": "Cancel" | "Select default plane" | "xstate.stop";
 | 
			
		||||
"reset sketch metadata": "Cancel" | "Select default plane";
 | 
			
		||||
"set default plane id": "Select default plane";
 | 
			
		||||
@ -66,11 +71,14 @@
 | 
			
		||||
          
 | 
			
		||||
        };
 | 
			
		||||
        eventsCausingGuards: {
 | 
			
		||||
          "Can constrain angle": "Constrain angle";
 | 
			
		||||
          "Can canstrain parallel": "Constrain parallel";
 | 
			
		||||
"Can constrain angle": "Constrain angle";
 | 
			
		||||
"Can constrain equal length": "Constrain equal length";
 | 
			
		||||
"Can constrain horizontal distance": "Constrain horizontal distance";
 | 
			
		||||
"Can constrain horizontally align": "Constrain horizontally align";
 | 
			
		||||
"Can constrain length": "Constrain length";
 | 
			
		||||
"Can constrain perpendicular distance": "Constrain perpendicular distance";
 | 
			
		||||
"Can constrain remove constraints": "Constrain remove constraints";
 | 
			
		||||
"Can constrain vertical distance": "Constrain vertical distance";
 | 
			
		||||
"Can constrain vertically align": "Constrain vertically align";
 | 
			
		||||
"Can make selection horizontal": "Make segment horizontal";
 | 
			
		||||
@ -92,9 +100,10 @@
 | 
			
		||||
          "Get angle info": "Constrain angle";
 | 
			
		||||
"Get horizontal info": "Constrain horizontal distance";
 | 
			
		||||
"Get length info": "Constrain length";
 | 
			
		||||
"Get perpendicular distance info": "Constrain perpendicular distance";
 | 
			
		||||
"Get vertical info": "Constrain vertical distance";
 | 
			
		||||
        };
 | 
			
		||||
        matchesStates: "Sketch" | "Sketch no face" | "Sketch.Await angle info" | "Sketch.Await horizontal distance info" | "Sketch.Await length info" | "Sketch.Await vertical distance info" | "Sketch.Line Tool" | "Sketch.Line Tool.Done" | "Sketch.Line Tool.Init" | "Sketch.Line Tool.No Points" | "Sketch.Line Tool.Point Added" | "Sketch.Line Tool.Segment Added" | "Sketch.Move Tool" | "Sketch.Move Tool.Move init" | "Sketch.Move Tool.Move with execute" | "Sketch.Move Tool.Move without re-execute" | "Sketch.Move Tool.No move" | "Sketch.SketchIdle" | "awaiting selection" | "checking selection" | "idle" | { "Sketch"?: "Await angle info" | "Await horizontal distance info" | "Await length info" | "Await vertical distance info" | "Line Tool" | "Move Tool" | "SketchIdle" | { "Line Tool"?: "Done" | "Init" | "No Points" | "Point Added" | "Segment Added";
 | 
			
		||||
        matchesStates: "Sketch" | "Sketch no face" | "Sketch.Await angle info" | "Sketch.Await horizontal distance info" | "Sketch.Await length info" | "Sketch.Await perpendicular distance info" | "Sketch.Await vertical distance info" | "Sketch.Line Tool" | "Sketch.Line Tool.Done" | "Sketch.Line Tool.Init" | "Sketch.Line Tool.No Points" | "Sketch.Line Tool.Point Added" | "Sketch.Line Tool.Segment Added" | "Sketch.Move Tool" | "Sketch.Move Tool.Move init" | "Sketch.Move Tool.Move with execute" | "Sketch.Move Tool.Move without re-execute" | "Sketch.Move Tool.No move" | "Sketch.SketchIdle" | "awaiting selection" | "checking selection" | "idle" | { "Sketch"?: "Await angle info" | "Await horizontal distance info" | "Await length info" | "Await perpendicular distance info" | "Await vertical distance info" | "Line Tool" | "Move Tool" | "SketchIdle" | { "Line Tool"?: "Done" | "Init" | "No Points" | "Point Added" | "Segment Added";
 | 
			
		||||
"Move Tool"?: "Move init" | "Move with execute" | "Move without re-execute" | "No move"; }; };
 | 
			
		||||
        tags: never;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user