Select axis and relevant constraints (#1154)

* update select logic for axis

* add abs Y and X constraints

* make selection tests much more thorough including axis selections

* fmt

* tweak

* tweak

* add snap to XY constraints

* side just for screenshot diffs

* update angle constraint to allow axis seleciton

* fix bux in absY constraint

* add sorting to constraintns

* add issue to TODO

* Revert "side just for screenshot diffs"

This reverts commit aae7874859.

* fix number because something must have updated in the engine

* typo

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* Revert "add sorting to constraintns"

This reverts commit 36054a4069.

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* triggre CI

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Kurt Hutten
2023-12-01 20:18:51 +11:00
committed by GitHub
parent f3083eb59d
commit 3eb92bb0c4
10 changed files with 391 additions and 72 deletions

View File

@ -4,6 +4,8 @@ import { EngineCommand } from '../../src/lang/std/engineConnection'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import { getUtils } from './test-utils' import { getUtils } from './test-utils'
import waitOn from 'wait-on' import waitOn from 'wait-on'
import { Models } from '@kittycad/lib'
import fsp from 'fs/promises'
/* /*
debug helper: unfortunately we do rely on exact coord mouse clicks in a few places debug helper: unfortunately we do rely on exact coord mouse clicks in a few places
@ -79,8 +81,8 @@ test('Basic sketch', async ({ page }) => {
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10) await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
const startAt = '[9.94, -13.41]' const startAt = '[10.97, -14.79]'
const tenish = '10.03' const tenish = '11.07'
await expect(page.locator('.cm-content')) await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('-XZ') .toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt(${startAt}, %) |> startProfileAt(${startAt}, %)
@ -98,7 +100,7 @@ test('Basic sketch', async ({ page }) => {
|> startProfileAt(${startAt}, %) |> startProfileAt(${startAt}, %)
|> line([${tenish}, 0], %) |> line([${tenish}, 0], %)
|> line([0, ${tenish}], %) |> line([0, ${tenish}], %)
|> line([-19.97, 0], %)`) |> line([-22.04, 0], %)`)
// deselect line tool // deselect line tool
await u.doAndWaitForCmd( await u.doAndWaitForCmd(
@ -126,7 +128,7 @@ test('Basic sketch', async ({ page }) => {
await expect(page.locator('.cm-content')) await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('-XZ') .toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt(${startAt}, %) |> startProfileAt(${startAt}, %)
|> line({ to: [10.03, 0], tag: 'seg01' }, %) |> line({ to: [${tenish}, 0], tag: 'seg01' }, %)
|> line([0, ${tenish}], %) |> line([0, ${tenish}], %)
|> angledLine([180, segLen('seg01', %)], %)`) |> angledLine([180, segLen('seg01', %)], %)`)
}) })
@ -309,8 +311,8 @@ test('Can create sketches on all planes and their back sides', async ({
plane = 'XY', plane = 'XY',
sign = '' sign = ''
) => `const part001 = startSketchOn('${plane}') ) => `const part001 = startSketchOn('${plane}')
|> startProfileAt([${sign}3.97, -5.36], %) |> startProfileAt([${sign}6.88, -9.29], %)
|> line([${sign}4.01, 0], %)` |> line([${sign}6.95, 0], %)`
await TestSinglePlane({ await TestSinglePlane({
viewCmd: camCmd, viewCmd: camCmd,
expectedCode: codeTemplate('XY'), expectedCode: codeTemplate('XY'),
@ -454,6 +456,11 @@ test('Selections work on fresh and edited sketch', async ({ page }) => {
await u.openDebugPanel() await u.openDebugPanel()
await u.waitForDefaultPlanesVisibilityChange() await u.waitForDefaultPlanesVisibilityChange()
const xAxisClick = () => page.mouse.click(700, 250)
const emptySpaceClick = () => page.mouse.click(700, 300)
const topHorzSegmentClick = () => page.mouse.click(700, 285)
const bottomHorzSegmentClick = () => page.mouse.click(750, 393)
await u.clearCommandLogs() await u.clearCommandLogs()
await page.getByRole('button', { name: 'Start Sketch' }).click() await page.getByRole('button', { name: 'Start Sketch' }).click()
await u.waitForDefaultPlanesVisibilityChange() await u.waitForDefaultPlanesVisibilityChange()
@ -476,8 +483,9 @@ test('Selections work on fresh and edited sketch', async ({ page }) => {
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10) await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
const startAt = '[9.94, -13.41]' const startAt = '[10.97, -14.79]'
const tenish = '10.03' const tenish = '11.07'
const twentyish = '22.04'
await expect(page.locator('.cm-content')) await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('-XZ') .toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt(${startAt}, %) |> startProfileAt(${startAt}, %)
@ -495,7 +503,7 @@ test('Selections work on fresh and edited sketch', async ({ page }) => {
|> startProfileAt(${startAt}, %) |> startProfileAt(${startAt}, %)
|> line([${tenish}, 0], %) |> line([${tenish}, 0], %)
|> line([0, ${tenish}], %) |> line([0, ${tenish}], %)
|> line([-19.97, 0], %)`) |> line([-${twentyish}, 0], %)`)
// deselect line tool // deselect line tool
await u.doAndWaitForCmd( await u.doAndWaitForCmd(
@ -504,7 +512,7 @@ test('Selections work on fresh and edited sketch', async ({ page }) => {
) )
await u.closeDebugPanel() await u.closeDebugPanel()
const hoverSequency = async () => { const selectionSequence = async () => {
await expect(page.getByTestId('hover-highlight')).not.toBeVisible() await expect(page.getByTestId('hover-highlight')).not.toBeVisible()
await page.mouse.move(startXPx + PUR * 15, 500 - PUR * 10) await page.mouse.move(startXPx + PUR * 15, 500 - PUR * 10)
@ -519,20 +527,76 @@ test('Selections work on fresh and edited sketch', async ({ page }) => {
await expect(page.getByTestId('hover-highlight')).not.toBeVisible() await expect(page.getByTestId('hover-highlight')).not.toBeVisible()
await page.mouse.move(startXPx + PUR * 10, 500 - PUR * 20) // mouse onto another line await page.mouse.move(startXPx + PUR * 10, 500 - PUR * 20) // mouse onto another line
await expect(page.getByTestId('hover-highlight')).toBeVisible() await expect(page.getByTestId('hover-highlight')).toBeVisible()
// now check clicking works including axis
// click a segment hold shift and click an axis, see that a relevant constraint is enabled
await u.doAndWaitForCmd(topHorzSegmentClick, 'select_with_point', false)
await page.keyboard.down('Shift')
const absYButton = page.getByRole('button', { name: 'ABS Y' })
await expect(absYButton).toBeDisabled()
await u.doAndWaitForCmd(xAxisClick, 'select_with_point', false)
await page.keyboard.up('Shift')
await absYButton.and(page.locator(':not([disabled])')).waitFor()
await expect(absYButton).not.toBeDisabled()
// clear selection by clicking on nothing
await u.doAndWaitForCmd(emptySpaceClick, 'select_clear', false)
// same selection but click the axis first
await u.doAndWaitForCmd(xAxisClick, 'select_with_point', false)
await expect(absYButton).toBeDisabled()
await page.keyboard.down('Shift')
await u.doAndWaitForCmd(topHorzSegmentClick, 'select_with_point', false)
await page.keyboard.up('Shift')
await expect(absYButton).not.toBeDisabled()
// clear selection by clicking on nothing
await u.doAndWaitForCmd(emptySpaceClick, 'select_clear', false)
// check the same selection again by putting cursor in code first then selecting axis
await u.doAndWaitForCmd(
() => page.getByText(` |> line([-${twentyish}, 0], %)`).click(),
'select_clear',
false
)
await page.keyboard.down('Shift')
await expect(absYButton).toBeDisabled()
await u.doAndWaitForCmd(xAxisClick, 'select_with_point', false)
await page.keyboard.up('Shift')
await expect(absYButton).not.toBeDisabled()
// clear selection by clicking on nothing
await u.doAndWaitForCmd(emptySpaceClick, 'select_clear', false)
// select segment in editor than another segment in scene and check there are two cursors
await u.doAndWaitForCmd(
() => page.getByText(` |> line([-${twentyish}, 0], %)`).click(),
'select_clear',
false
)
await page.keyboard.down('Shift')
await expect(page.locator('.cm-cursor')).toHaveCount(1)
await u.doAndWaitForCmd(bottomHorzSegmentClick, 'select_with_point', false) // another segment, bottom one
await page.keyboard.up('Shift')
await expect(page.locator('.cm-cursor')).toHaveCount(2)
// clear selection by clicking on nothing
await u.doAndWaitForCmd(emptySpaceClick, 'select_clear', false)
} }
await hoverSequency()
await selectionSequence()
// hovering in fresh sketch worked, lets try exiting and re-entering // hovering in fresh sketch worked, lets try exiting and re-entering
await u.doAndWaitForCmd( await u.doAndWaitForCmd(
() => page.getByRole('button', { name: 'Exit Sketch' }).click(), () => page.getByRole('button', { name: 'Exit Sketch' }).click(),
'edit_mode_exit' 'edit_mode_exit'
) )
// wait for execution done
await u.expectCmdLog('[data-message-type="execution-done"]')
// select a line // select a line
await u.doAndWaitForCmd( await u.doAndWaitForCmd(topHorzSegmentClick, 'select_clear', false)
() => page.mouse.click(startXPx + PUR * 10, 500 - PUR * 20),
'select_with_point'
)
// enter sketch again // enter sketch again
await u.doAndWaitForCmd( await u.doAndWaitForCmd(
@ -542,5 +606,5 @@ test('Selections work on fresh and edited sketch', async ({ page }) => {
) )
// hover again and check it works // hover again and check it works
await hoverSequency() await selectionSequence()
}) })

View File

@ -32,14 +32,14 @@ export default defineConfig({
/* Configure projects for major browsers */ /* Configure projects for major browsers */
projects: [ projects: [
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
{ {
name: 'Google Chrome', name: 'Google Chrome',
use: { ...devices['Desktop Chrome'], channel: 'chrome' }, // or 'chrome-beta' use: { ...devices['Desktop Chrome'], channel: 'chrome' }, // or 'chrome-beta'
}, },
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
// { // {
// name: 'firefox', // name: 'firefox',
// use: { ...devices['Desktop Firefox'] }, // use: { ...devices['Desktop Firefox'] },

View File

@ -31,13 +31,17 @@ import {
} from 'lang/std/sketch' } from 'lang/std/sketch'
import { kclManager } from 'lang/KclSinglton' import { kclManager } from 'lang/KclSinglton'
import { applyConstraintHorzVertDistance } from './Toolbar/SetHorzVertDistance' import { applyConstraintHorzVertDistance } from './Toolbar/SetHorzVertDistance'
import { applyConstraintAngleBetween } from './Toolbar/SetAngleBetween' import {
angleBetweenInfo,
applyConstraintAngleBetween,
} from './Toolbar/SetAngleBetween'
import { applyConstraintAngleLength } from './Toolbar/setAngleLength' import { applyConstraintAngleLength } from './Toolbar/setAngleLength'
import { toast } from 'react-hot-toast' import { toast } from 'react-hot-toast'
import { pathMapToSelections } from 'lang/util' import { pathMapToSelections } from 'lang/util'
import { useStore } from 'useStore' import { useStore } from 'useStore'
import { handleSelectionBatch, handleSelectionWithShift } from 'lib/selections' import { handleSelectionBatch, handleSelectionWithShift } from 'lib/selections'
import { applyConstraintIntersect } from './Toolbar/Intersect' import { applyConstraintIntersect } from './Toolbar/Intersect'
import { applyConstraintAbsDistance } from './Toolbar/SetAbsDistance'
type MachineContext<T extends AnyStateMachine> = { type MachineContext<T extends AnyStateMachine> = {
state: StateFrom<T> state: StateFrom<T>
@ -262,17 +266,62 @@ export const ModelingMachineProvider = ({
'Set selection': assign(({ selectionRanges }, event) => { 'Set selection': assign(({ selectionRanges }, event) => {
if (event.type !== 'Set selection') return {} // this was needed for ts after adding 'Set selection' action to on done modal events if (event.type !== 'Set selection') return {} // this was needed for ts after adding 'Set selection' action to on done modal events
const setSelections = event.data const setSelections = event.data
if (!editorView) return {}
if (setSelections.selectionType === 'mirrorCodeMirrorSelections') if (setSelections.selectionType === 'mirrorCodeMirrorSelections')
return { selectionRanges: setSelections.selection } return { selectionRanges: setSelections.selection }
else if (setSelections.selectionType === 'otherSelection') else if (setSelections.selectionType === 'otherSelection') {
// TODO KittyCAD/engine/issues/1620: send axis highlight when it's working (if that's what we settle on)
// const axisAddCmd: EngineCommand = {
// type: 'modeling_cmd_req',
// cmd: {
// type: 'highlight_set_entities',
// entities: [
// setSelections.selection === 'x-axis'
// ? X_AXIS_UUID
// : Y_AXIS_UUID,
// ],
// },
// cmd_id: uuidv4(),
// }
// if (!isShiftDown) {
// engineCommandManager
// .sendSceneCommand({
// type: 'modeling_cmd_req',
// cmd: {
// type: 'select_clear',
// },
// cmd_id: uuidv4(),
// })
// .then(() => {
// engineCommandManager.sendSceneCommand(axisAddCmd)
// })
// } else {
// engineCommandManager.sendSceneCommand(axisAddCmd)
// }
const {
codeMirrorSelection,
selectionRangeTypeMap,
otherSelections,
} = handleSelectionWithShift({
otherSelection: setSelections.selection,
currentSelections: selectionRanges,
isShiftDown,
})
setTimeout(() => {
editorView.dispatch({
selection: codeMirrorSelection,
})
})
return { return {
selectionRangeTypeMap,
selectionRanges: { selectionRanges: {
...selectionRanges, codeBasedSelections: selectionRanges.codeBasedSelections,
otherSelections: [setSelections.selection], otherSelections,
}, },
} }
else if (!editorView) return {} } else if (setSelections.selectionType === 'singleCodeCursor') {
else if (setSelections.selectionType === 'singleCodeCursor') {
// This DOES NOT set the `selectionRanges` in xstate context // This DOES NOT set the `selectionRanges` in xstate context
// instead it updates/dispatches to the editor, which in turn updates the xstate context // instead it updates/dispatches to the editor, which in turn updates the xstate context
// I've found this the best way to deal with the editor without causing an infinite loop // I've found this the best way to deal with the editor without causing an infinite loop
@ -280,12 +329,16 @@ export const ModelingMachineProvider = ({
// because we want to respect the user manually placing the cursor too. // because we want to respect the user manually placing the cursor too.
// for more details on how selections see `src/lib/selections.ts`. // for more details on how selections see `src/lib/selections.ts`.
const { codeMirrorSelection, selectionRangeTypeMap } =
handleSelectionWithShift({ const {
codeSelection: setSelections.selection, codeMirrorSelection,
currestSelections: selectionRanges, selectionRangeTypeMap,
isShiftDown, otherSelections,
}) } = handleSelectionWithShift({
codeSelection: setSelections.selection,
currentSelections: selectionRanges,
isShiftDown,
})
if (codeMirrorSelection) { if (codeMirrorSelection) {
setTimeout(() => { setTimeout(() => {
editorView.dispatch({ editorView.dispatch({
@ -293,7 +346,22 @@ export const ModelingMachineProvider = ({
}) })
}) })
} }
return { selectionRangeTypeMap } if (!setSelections.selection) {
return {
selectionRangeTypeMap,
selectionRanges: {
codeBasedSelections: selectionRanges.codeBasedSelections,
otherSelections,
},
}
}
return {
selectionRangeTypeMap,
selectionRanges: {
codeBasedSelections: selectionRanges.codeBasedSelections,
otherSelections,
},
}
} }
// This DOES NOT set the `selectionRanges` in xstate context // This DOES NOT set the `selectionRanges` in xstate context
// same as comment above // same as comment above
@ -363,10 +431,16 @@ export const ModelingMachineProvider = ({
} }
}, },
'Get angle info': async ({ selectionRanges }): Promise<SetSelections> => { 'Get angle info': async ({ selectionRanges }): Promise<SetSelections> => {
const { modifiedAst, pathToNodeMap } = const { modifiedAst, pathToNodeMap } = await (angleBetweenInfo({
await applyConstraintAngleBetween({ selectionRanges,
selectionRanges, }).enabled
}) ? applyConstraintAngleBetween({
selectionRanges,
})
: applyConstraintAngleLength({
selectionRanges,
angleOrLength: 'setAngle',
}))
await kclManager.updateAst(modifiedAst, true) await kclManager.updateAst(modifiedAst, true)
return { return {
selectionType: 'completeSelection', selectionType: 'completeSelection',
@ -409,6 +483,40 @@ export const ModelingMachineProvider = ({
), ),
} }
}, },
'Get ABS X info': async ({ selectionRanges }): Promise<SetSelections> => {
const { modifiedAst, pathToNodeMap } = await applyConstraintAbsDistance(
{
constraint: 'xAbs',
selectionRanges,
}
)
await kclManager.updateAst(modifiedAst, true)
return {
selectionType: 'completeSelection',
selection: pathMapToSelections(
kclManager.ast,
selectionRanges,
pathToNodeMap
),
}
},
'Get ABS Y info': async ({ selectionRanges }): Promise<SetSelections> => {
const { modifiedAst, pathToNodeMap } = await applyConstraintAbsDistance(
{
constraint: 'yAbs',
selectionRanges,
}
)
await kclManager.updateAst(modifiedAst, true)
return {
selectionType: 'completeSelection',
selection: pathMapToSelections(
kclManager.ast,
selectionRanges,
pathToNodeMap
),
}
},
}, },
devTools: true, devTools: true,
}) })

View File

@ -42,13 +42,19 @@ export const TextEditor = ({
}: { }: {
theme: Themes.Light | Themes.Dark theme: Themes.Light | Themes.Dark
}) => { }) => {
const { editorView, isLSPServerReady, setEditorView, setIsLSPServerReady } = const {
useStore((s) => ({ editorView,
editorView: s.editorView, isLSPServerReady,
isLSPServerReady: s.isLSPServerReady, setEditorView,
setEditorView: s.setEditorView, setIsLSPServerReady,
setIsLSPServerReady: s.setIsLSPServerReady, isShiftDown,
})) } = useStore((s) => ({
editorView: s.editorView,
isLSPServerReady: s.isLSPServerReady,
setEditorView: s.setEditorView,
setIsLSPServerReady: s.setIsLSPServerReady,
isShiftDown: s.isShiftDown,
}))
const { code, errors } = useKclContext() const { code, errors } = useKclContext()
const { const {
@ -113,6 +119,7 @@ export const TextEditor = ({
codeMirrorRanges: viewUpdate.state.selection.ranges, codeMirrorRanges: viewUpdate.state.selection.ranges,
selectionRanges, selectionRanges,
selectionRangeTypeMap, selectionRangeTypeMap,
isShiftDown,
}) })
if (!eventInfo) return if (!eventInfo) return

View File

@ -59,6 +59,7 @@ export function angleBetweenInfo({
) )
const _enableEqual = const _enableEqual =
selectionRanges.otherSelections.length === 0 &&
secondaryVarDecs.length === 1 && secondaryVarDecs.length === 1 &&
isAllTooltips && isAllTooltips &&
isOthersLinkedToPrimary && isOthersLinkedToPrimary &&

View File

@ -25,7 +25,7 @@ import { kclManager } from 'lang/KclSinglton'
const getModalInfo = createSetAngleLengthModal(SetAngleLengthModal) const getModalInfo = createSetAngleLengthModal(SetAngleLengthModal)
export function setAngleLengthInfo({ export function angleLengthInfo({
selectionRanges, selectionRanges,
angleOrLength = 'setLength', angleOrLength = 'setLength',
}: { }: {
@ -50,7 +50,10 @@ export function setAngleLengthInfo({
kclManager.ast, kclManager.ast,
angleOrLength angleOrLength
) )
const enabled = isAllTooltips && transforms.every(Boolean) const enabled =
selectionRanges.codeBasedSelections.length <= 1 &&
isAllTooltips &&
transforms.every(Boolean)
return { enabled, transforms } return { enabled, transforms }
} }
@ -64,7 +67,7 @@ export async function applyConstraintAngleLength({
modifiedAst: Program modifiedAst: Program
pathToNodeMap: PathToNodeMap pathToNodeMap: PathToNodeMap
}> { }> {
const { transforms } = setAngleLengthInfo({ selectionRanges, angleOrLength }) const { transforms } = angleLengthInfo({ selectionRanges, angleOrLength })
const { valueUsedInTransform } = transformAstSketchLines({ const { valueUsedInTransform } = transformAstSketchLines({
ast: JSON.parse(JSON.stringify(kclManager.ast)), ast: JSON.parse(JSON.stringify(kclManager.ast)),
selectionRanges, selectionRanges,

View File

@ -334,10 +334,7 @@ const setAbsDistanceForAngleLineCreateNode =
): TransformInfo['createNode'] => ): TransformInfo['createNode'] =>
({ tag, forceValueUsedInTransform, varValA }) => { ({ tag, forceValueUsedInTransform, varValA }) => {
return (args, referencedSegment) => { return (args, referencedSegment) => {
const valueUsedInTransform = roundOff( const valueUsedInTransform = roundOff(getArgLiteralVal(args?.[1]), 2)
getArgLiteralVal(args?.[1]) - (referencedSegment?.to?.[index] || 0),
2
)
const val = const val =
(forceValueUsedInTransform as BinaryPart) || (forceValueUsedInTransform as BinaryPart) ||
createLiteral(valueUsedInTransform) createLiteral(valueUsedInTransform)

View File

@ -8,6 +8,9 @@ import { kclManager } from 'lang/KclSinglton'
import { SelectionRange } from '@uiw/react-codemirror' import { SelectionRange } from '@uiw/react-codemirror'
import { isOverlap } from 'lib/utils' import { isOverlap } from 'lib/utils'
export const X_AXIS_UUID = 'ad792545-7fd3-482a-a602-a93924e3055b'
export const Y_AXIS_UUID = '680fd157-266f-4b8a-984f-cdf46b8bdf01'
/* /*
How selections work is complex due to the nature that we rely on the engine How selections work is complex due to the nature that we rely on the engine
to tell what has been selected after we send a click command. But than the to tell what has been selected after we send a click command. But than the
@ -110,6 +113,15 @@ export async function getEventForSelectWithPoint(
data: { selectionType: 'singleCodeCursor' }, data: { selectionType: 'singleCodeCursor' },
} }
} }
if ([X_AXIS_UUID, Y_AXIS_UUID].includes(data.entity_id)) {
return {
type: 'Set selection',
data: {
selectionType: 'otherSelection',
selection: X_AXIS_UUID === data.entity_id ? 'x-axis' : 'y-axis',
},
}
}
const sourceRange = engineCommandManager.artifactMap[data.entity_id]?.range const sourceRange = engineCommandManager.artifactMap[data.entity_id]?.range
if (engineCommandManager.artifactMap[data.entity_id]) { if (engineCommandManager.artifactMap[data.entity_id]) {
return { return {
@ -164,6 +176,7 @@ export function handleSelectionBatch({
}): { }): {
selectionRangeTypeMap: SelectionRangeTypeMap selectionRangeTypeMap: SelectionRangeTypeMap
codeMirrorSelection?: EditorSelection codeMirrorSelection?: EditorSelection
otherSelections: Axis[]
} { } {
const ranges: ReturnType<typeof EditorSelection.cursor>[] = [] const ranges: ReturnType<typeof EditorSelection.cursor>[] = []
const selectionRangeTypeMap: SelectionRangeTypeMap = {} const selectionRangeTypeMap: SelectionRangeTypeMap = {}
@ -180,43 +193,74 @@ export function handleSelectionBatch({
ranges, ranges,
selections.codeBasedSelections.length - 1 selections.codeBasedSelections.length - 1
), ),
otherSelections: selections.otherSelections,
} }
return { return {
selectionRangeTypeMap, selectionRangeTypeMap,
otherSelections: selections.otherSelections,
} }
} }
export function handleSelectionWithShift({ export function handleSelectionWithShift({
codeSelection, codeSelection,
currestSelections, otherSelection,
currentSelections,
isShiftDown, isShiftDown,
}: { }: {
codeSelection?: Selection codeSelection?: Selection
currestSelections: Selections otherSelection?: Axis
currentSelections: Selections
isShiftDown: boolean isShiftDown: boolean
}): { }): {
selectionRangeTypeMap: SelectionRangeTypeMap selectionRangeTypeMap: SelectionRangeTypeMap
otherSelections: Axis[]
codeMirrorSelection?: EditorSelection codeMirrorSelection?: EditorSelection
} { } {
const code = kclManager.code const code = kclManager.code
if (!codeSelection) if (codeSelection && otherSelection) {
throw new Error('cannot have both code and other selection')
}
if (!codeSelection && !otherSelection) {
return handleSelectionBatch({ return handleSelectionBatch({
selections: { selections: {
otherSelections: currestSelections.otherSelections, otherSelections: [],
codeBasedSelections: [ codeBasedSelections: [
{ {
range: [0, code.length ? code.length - 1 : 0], range: [0, code.length ? code.length : 0],
type: 'default', type: 'default',
}, },
], ],
}, },
}) })
}
if (otherSelection) {
console.log('otherSelection in handleSelectionWithShift', otherSelection)
return handleSelectionBatch({
selections: {
codeBasedSelections: isShiftDown
? currentSelections.codeBasedSelections
: [
{
range: [0, code.length ? code.length : 0],
type: 'default',
},
],
otherSelections: [otherSelection],
},
})
}
const isEndOfFileDumbySelection =
currentSelections.codeBasedSelections.length === 1 &&
currentSelections.codeBasedSelections[0].range[0] === kclManager.code.length
const newCodeBasedSelections = !isShiftDown
? [codeSelection!]
: isEndOfFileDumbySelection
? [codeSelection!]
: [...currentSelections.codeBasedSelections, codeSelection!]
const selections: Selections = { const selections: Selections = {
...currestSelections, otherSelections: isShiftDown ? currentSelections.otherSelections : [],
codeBasedSelections: isShiftDown codeBasedSelections: newCodeBasedSelections,
? [...currestSelections.codeBasedSelections, codeSelection]
: [codeSelection],
} }
return handleSelectionBatch({ selections }) return handleSelectionBatch({ selections })
} }
@ -227,10 +271,12 @@ export function processCodeMirrorRanges({
codeMirrorRanges, codeMirrorRanges,
selectionRanges, selectionRanges,
selectionRangeTypeMap, selectionRangeTypeMap,
isShiftDown,
}: { }: {
codeMirrorRanges: readonly SelectionRange[] codeMirrorRanges: readonly SelectionRange[]
selectionRanges: Selections selectionRanges: Selections
selectionRangeTypeMap: SelectionRangeTypeMap selectionRangeTypeMap: SelectionRangeTypeMap
isShiftDown: boolean
}): null | { }): null | {
modelingEvent: ModelingMachineEvent modelingEvent: ModelingMachineEvent
engineEvents: Models['WebSocketRequest_type'][] engineEvents: Models['WebSocketRequest_type'][]
@ -291,7 +337,7 @@ export function processCodeMirrorRanges({
data: { data: {
selectionType: 'mirrorCodeMirrorSelections', selectionType: 'mirrorCodeMirrorSelections',
selection: { selection: {
...selectionRanges, otherSelections: isShiftDown ? selectionRanges.otherSelections : [],
codeBasedSelections, codeBasedSelections,
}, },
}, },
@ -300,7 +346,7 @@ export function processCodeMirrorRanges({
} }
} }
export function resetAndSetEngineEntitySelectionCmds( function resetAndSetEngineEntitySelectionCmds(
selections: SelectionToEngine[] selections: SelectionToEngine[]
): Models['WebSocketRequest_type'][] { ): Models['WebSocketRequest_type'][] {
if (!engineCommandManager.engineConnection?.isReady()) { if (!engineCommandManager.engineConnection?.isReady()) {

File diff suppressed because one or more lines are too long

View File

@ -5,11 +5,15 @@
'@@xstate/typegen': true; '@@xstate/typegen': true;
internalEvents: { internalEvents: {
"": { type: "" }; "": { type: "" };
"done.invoke.get-abs-x-info": { type: "done.invoke.get-abs-x-info"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
"done.invoke.get-abs-y-info": { type: "done.invoke.get-abs-y-info"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
"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-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-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-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-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." }; "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-abs-x-info": { type: "error.platform.get-abs-x-info"; data: unknown };
"error.platform.get-abs-y-info": { type: "error.platform.get-abs-y-info"; data: unknown };
"error.platform.get-angle-info": { type: "error.platform.get-angle-info"; data: unknown }; "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-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-length-info": { type: "error.platform.get-length-info"; data: unknown };
@ -19,7 +23,9 @@
"xstate.stop": { type: "xstate.stop" }; "xstate.stop": { type: "xstate.stop" };
}; };
invokeSrcNameMap: { invokeSrcNameMap: {
"Get angle info": "done.invoke.get-angle-info"; "Get ABS X info": "done.invoke.get-abs-x-info";
"Get ABS Y info": "done.invoke.get-abs-y-info";
"Get angle info": "done.invoke.get-angle-info";
"Get horizontal info": "done.invoke.get-horizontal-info"; "Get horizontal info": "done.invoke.get-horizontal-info";
"Get length info": "done.invoke.get-length-info"; "Get length info": "done.invoke.get-length-info";
"Get perpendicular distance info": "done.invoke.get-perpendicular-distance-info"; "Get perpendicular distance info": "done.invoke.get-perpendicular-distance-info";
@ -29,7 +35,7 @@
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"; 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; 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"; 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 perpendicular distance info" | "Get vertical info"; services: "Get ABS X info" | "Get ABS Y info" | "Get angle info" | "Get horizontal info" | "Get length info" | "Get perpendicular distance info" | "Get vertical info";
}; };
eventsCausingActions: { eventsCausingActions: {
"AST add line segment": "Add point"; "AST add line segment": "Add point";
@ -42,19 +48,21 @@
"Constrain horizontally align": "Constrain horizontally align"; "Constrain horizontally align": "Constrain horizontally align";
"Constrain parallel": "Constrain parallel"; "Constrain parallel": "Constrain parallel";
"Constrain remove constraints": "Constrain remove constraints"; "Constrain remove constraints": "Constrain remove constraints";
"Constrain snap to X": "Constrain snap to X";
"Constrain snap to Y": "Constrain snap to Y";
"Constrain vertically align": "Constrain vertically align"; "Constrain vertically align": "Constrain vertically align";
"Make selection horizontal": "Make segment horizontal"; "Make selection horizontal": "Make segment horizontal";
"Make selection vertical": "Make segment vertical"; "Make selection vertical": "Make segment vertical";
"Modify AST": "Complete line"; "Modify AST": "Complete line";
"Remove from code-based selection": "Deselect edge" | "Deselect face" | "Deselect point"; "Remove from code-based selection": "Deselect edge" | "Deselect face" | "Deselect point";
"Remove from other selection": "Deselect axis"; "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-perpendicular-distance-info" | "done.invoke.get-vertical-info"; "Set selection": "Set selection" | "done.invoke.get-abs-x-info" | "done.invoke.get-abs-y-info" | "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"; "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"; "create path": "Select default plane";
"default_camera_disable_sketch_mode": "Cancel"; "default_camera_disable_sketch_mode": "Cancel";
"edit mode enter": "Enter sketch" | "Re-execute"; "edit mode enter": "Enter sketch" | "Re-execute";
"edit_mode_exit": "Cancel"; "edit_mode_exit": "Cancel";
"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" | "Re-execute" | "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"; "equip select": "CancelSketch" | "Constrain equal length" | "Constrain horizontally align" | "Constrain parallel" | "Constrain remove constraints" | "Constrain snap to X" | "Constrain snap to Y" | "Constrain vertically align" | "Deselect point" | "Deselect segment" | "Enter sketch" | "Make segment horizontal" | "Make segment vertical" | "Re-execute" | "Select default plane" | "Select point" | "Select segment" | "Set selection" | "done.invoke.get-abs-x-info" | "done.invoke.get-abs-y-info" | "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-abs-x-info" | "error.platform.get-abs-y-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"; "hide default planes": "Cancel" | "Select default plane" | "xstate.stop";
"reset sketch metadata": "Cancel" | "Select default plane"; "reset sketch metadata": "Cancel" | "Select default plane";
"set default plane id": "Select default plane"; "set default plane id": "Select default plane";
@ -73,6 +81,8 @@
}; };
eventsCausingGuards: { eventsCausingGuards: {
"Can canstrain parallel": "Constrain parallel"; "Can canstrain parallel": "Constrain parallel";
"Can constrain ABS X": "Constrain ABS X";
"Can constrain ABS Y": "Constrain ABS Y";
"Can constrain angle": "Constrain angle"; "Can constrain angle": "Constrain angle";
"Can constrain equal length": "Constrain equal length"; "Can constrain equal length": "Constrain equal length";
"Can constrain horizontal distance": "Constrain horizontal distance"; "Can constrain horizontal distance": "Constrain horizontal distance";
@ -80,6 +90,8 @@
"Can constrain length": "Constrain length"; "Can constrain length": "Constrain length";
"Can constrain perpendicular distance": "Constrain perpendicular distance"; "Can constrain perpendicular distance": "Constrain perpendicular distance";
"Can constrain remove constraints": "Constrain remove constraints"; "Can constrain remove constraints": "Constrain remove constraints";
"Can constrain snap to X": "Constrain snap to X";
"Can constrain snap to Y": "Constrain snap to Y";
"Can constrain vertical distance": "Constrain vertical distance"; "Can constrain vertical distance": "Constrain vertical distance";
"Can constrain vertically align": "Constrain vertically align"; "Can constrain vertically align": "Constrain vertically align";
"Can make selection horizontal": "Make segment horizontal"; "Can make selection horizontal": "Make segment horizontal";
@ -98,13 +110,15 @@
"is editing existing sketch": ""; "is editing existing sketch": "";
}; };
eventsCausingServices: { eventsCausingServices: {
"Get angle info": "Constrain angle"; "Get ABS X info": "Constrain ABS X";
"Get ABS Y info": "Constrain ABS Y";
"Get angle info": "Constrain angle";
"Get horizontal info": "Constrain horizontal distance"; "Get horizontal info": "Constrain horizontal distance";
"Get length info": "Constrain length"; "Get length info": "Constrain length";
"Get perpendicular distance info": "Constrain perpendicular distance"; "Get perpendicular distance info": "Constrain perpendicular distance";
"Get vertical info": "Constrain vertical 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 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"; matchesStates: "Sketch" | "Sketch no face" | "Sketch.Await ABS X info" | "Sketch.Await ABS Y info" | "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 ABS X info" | "Await ABS Y info" | "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"; }; }; "Move Tool"?: "Move init" | "Move with execute" | "Move without re-execute" | "No move"; }; };
tags: never; tags: never;
} }