Merge remote-tracking branch 'origin' into kurt-bring-back-multi-profile
This commit is contained in:
Binary file not shown.
Before Width: | Height: | Size: 144 KiB After Width: | Height: | Size: 144 KiB |
@ -1,6 +1,17 @@
|
||||
import { test, expect } from '@playwright/test'
|
||||
|
||||
import { getUtils, setup, tearDown, TEST_COLORS } from './test-utils'
|
||||
import {
|
||||
test as testFixture,
|
||||
expect as expectFixture,
|
||||
} from './fixtures/fixtureSetup'
|
||||
import { join } from 'path'
|
||||
import {
|
||||
getUtils,
|
||||
setup,
|
||||
tearDown,
|
||||
TEST_COLORS,
|
||||
executorInputPath,
|
||||
} from './test-utils'
|
||||
import * as fsp from 'fs/promises'
|
||||
import { XOR } from 'lib/utils'
|
||||
|
||||
test.beforeEach(async ({ context, page }, testInfo) => {
|
||||
@ -1028,3 +1039,58 @@ part002 = startSketchOn('XZ')
|
||||
await expect(page.getByTestId('segment-overlay')).toHaveCount(2)
|
||||
})
|
||||
})
|
||||
testFixture.describe('Electron constraint tests', () => {
|
||||
testFixture(
|
||||
'Able to double click label to set constraint',
|
||||
{ tag: '@electron' },
|
||||
async ({ tronApp, homePage, scene, editor, toolbar }) => {
|
||||
await tronApp.initialise({
|
||||
fixtures: { homePage, scene, editor, toolbar },
|
||||
folderSetupFn: async (dir) => {
|
||||
const bracketDir = join(dir, 'test-sample')
|
||||
await fsp.mkdir(bracketDir, { recursive: true })
|
||||
await fsp.copyFile(
|
||||
executorInputPath('angled_line.kcl'),
|
||||
join(bracketDir, 'main.kcl')
|
||||
)
|
||||
},
|
||||
})
|
||||
const [clickHandler] = scene.makeMouseHelpers(600, 300)
|
||||
|
||||
await test.step('setup test', async () => {
|
||||
await homePage.expectState({
|
||||
projectCards: [
|
||||
{
|
||||
title: 'test-sample',
|
||||
fileCount: 1,
|
||||
},
|
||||
],
|
||||
sortBy: 'last-modified-desc',
|
||||
})
|
||||
await homePage.openProject('test-sample')
|
||||
await scene.waitForExecutionDone()
|
||||
})
|
||||
|
||||
await test.step('Double click to constrain', async () => {
|
||||
await clickHandler()
|
||||
await tronApp.page.getByRole('button', { name: 'Edit Sketch' }).click()
|
||||
const child = tronApp.page
|
||||
.locator('.segment-length-label-text')
|
||||
.first()
|
||||
.locator('xpath=..')
|
||||
await child.dblclick()
|
||||
const cmdBarSubmitButton = tronApp.page.getByRole('button', {
|
||||
name: 'arrow right Continue',
|
||||
})
|
||||
await cmdBarSubmitButton.click()
|
||||
await expectFixture(tronApp.page.locator('.cm-content')).toContainText(
|
||||
'length001 = 15.3'
|
||||
)
|
||||
await expectFixture(tronApp.page.locator('.cm-content')).toContainText(
|
||||
'|> angledLine([9, length001], %)'
|
||||
)
|
||||
await tronApp.page.getByRole('button', { name: 'Exit Sketch' }).click()
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
|
@ -174,8 +174,13 @@ export const ClientSideScene = ({
|
||||
const Overlays = () => {
|
||||
const { context } = useModelingContext()
|
||||
if (context.mouseState.type === 'isDragging') return null
|
||||
// Set a large zIndex, the overlay for hover dropdown menu on line segments needs to render
|
||||
// over the length labels on the line segments
|
||||
return (
|
||||
<div className="absolute inset-0 pointer-events-none">
|
||||
<div
|
||||
className="absolute inset-0 pointer-events-none"
|
||||
style={{ zIndex: '99999999' }}
|
||||
>
|
||||
{Object.entries(context.segmentOverlays)
|
||||
.filter((a) => a[1].visible)
|
||||
.map(([pathToNodeString, overlay], index) => {
|
||||
|
@ -49,6 +49,7 @@ import {
|
||||
defaultSourceRange,
|
||||
sourceRangeFromRust,
|
||||
resultIsOk,
|
||||
SourceRange,
|
||||
} from 'lang/wasm'
|
||||
import {
|
||||
engineCommandManager,
|
||||
@ -110,6 +111,7 @@ import { SegmentInputs } from 'lang/std/stdTypes'
|
||||
import { Node } from 'wasm-lib/kcl/bindings/Node'
|
||||
import { radToDeg } from 'three/src/math/MathUtils'
|
||||
import toast from 'react-hot-toast'
|
||||
import { getArtifactFromRange, codeRefFromRange } from 'lang/std/artifactGraph'
|
||||
|
||||
type DraftSegment = 'line' | 'tangentialArcTo'
|
||||
|
||||
@ -648,7 +650,7 @@ export class SceneEntities {
|
||||
)
|
||||
|
||||
let seg: Group
|
||||
const _node1 = getNodeFromPath<CallExpression>(
|
||||
const _node1 = getNodeFromPath<Node<CallExpression>>(
|
||||
maybeModdedAst,
|
||||
segPathToNode,
|
||||
'CallExpression'
|
||||
@ -675,6 +677,13 @@ export class SceneEntities {
|
||||
from: segment.from,
|
||||
to: segment.to,
|
||||
}
|
||||
const startRange = _node1.node.start
|
||||
const endRange = _node1.node.end
|
||||
const sourceRange: SourceRange = [startRange, endRange, true]
|
||||
const selection: Selections = computeSelectionFromSourceRangeAndAST(
|
||||
sourceRange,
|
||||
maybeModdedAst
|
||||
)
|
||||
const result = initSegment({
|
||||
prevSegment: sketch.paths[index - 1],
|
||||
callExpName,
|
||||
@ -687,6 +696,7 @@ export class SceneEntities {
|
||||
theme: sceneInfra._theme,
|
||||
isSelected,
|
||||
sceneInfra,
|
||||
selection,
|
||||
})
|
||||
if (err(result)) return
|
||||
const { group: _group, updateOverlaysCallback } = result
|
||||
@ -2541,3 +2551,26 @@ function getSketchesInfo({
|
||||
}
|
||||
return sketchesInfo
|
||||
}
|
||||
/**
|
||||
* Given a SourceRange [x,y,boolean] create a Selections object which contains
|
||||
* graphSelections with the artifact and codeRef.
|
||||
* This can be passed to 'Set selection' to internally set the selection of the
|
||||
* modelingMachine from code.
|
||||
*/
|
||||
function computeSelectionFromSourceRangeAndAST(
|
||||
sourceRange: SourceRange,
|
||||
ast: Node<Program>
|
||||
): Selections {
|
||||
const artifactGraph = engineCommandManager.artifactGraph
|
||||
const artifact = getArtifactFromRange(sourceRange, artifactGraph) || undefined
|
||||
const selection: Selections = {
|
||||
graphSelections: [
|
||||
{
|
||||
artifact,
|
||||
codeRef: codeRefFromRange(sourceRange, ast),
|
||||
},
|
||||
],
|
||||
otherSelections: [],
|
||||
}
|
||||
return selection
|
||||
}
|
||||
|
@ -229,7 +229,6 @@ export class SceneInfra {
|
||||
const vector = new Vector3(0, 0, 0)
|
||||
|
||||
// Get the position of the object3D in world space
|
||||
// console.log('arrowGroup', arrowGroup)
|
||||
arrowGroup.getWorldPosition(vector)
|
||||
|
||||
// Project that position to screen space
|
||||
@ -347,7 +346,6 @@ export class SceneInfra {
|
||||
requestAnimationFrame(this.animate)
|
||||
TWEEN.update() // This will update all tweens during the animation loop
|
||||
if (!this.isFovAnimationInProgress) {
|
||||
// console.log('animation frame', this.cameraControls.camera)
|
||||
this.camControls.update()
|
||||
this.renderer.render(this.scene, this.camControls.camera)
|
||||
this.labelRenderer.render(this.scene, this.camControls.camera)
|
||||
@ -434,7 +432,6 @@ export class SceneInfra {
|
||||
if (!this.selected.hasBeenDragged && hasBeenDragged) {
|
||||
this.selected.hasBeenDragged = true
|
||||
// this is where we could fire a onDragStart event
|
||||
// console.log('onDragStart', this.selected)
|
||||
}
|
||||
if (
|
||||
hasBeenDragged &&
|
||||
|
@ -56,6 +56,8 @@ import { normaliseAngle, roundOff } from 'lib/utils'
|
||||
import { SegmentOverlayPayload } from 'machines/modelingMachine'
|
||||
import { SegmentInputs } from 'lang/std/stdTypes'
|
||||
import { err } from 'lib/trap'
|
||||
import { editorManager, sceneInfra } from 'lib/singletons'
|
||||
import { Selections } from 'lib/selections'
|
||||
|
||||
interface CreateSegmentArgs {
|
||||
input: SegmentInputs
|
||||
@ -69,6 +71,7 @@ interface CreateSegmentArgs {
|
||||
theme: Themes
|
||||
isSelected?: boolean
|
||||
sceneInfra: SceneInfra
|
||||
selection?: Selections
|
||||
}
|
||||
|
||||
interface UpdateSegmentArgs {
|
||||
@ -118,6 +121,7 @@ class StraightSegment implements SegmentUtils {
|
||||
isSelected = false,
|
||||
sceneInfra,
|
||||
prevSegment,
|
||||
selection,
|
||||
}) => {
|
||||
if (input.type !== 'straight-segment')
|
||||
return new Error('Invalid segment type')
|
||||
@ -156,6 +160,7 @@ class StraightSegment implements SegmentUtils {
|
||||
isSelected,
|
||||
callExpName,
|
||||
baseColor,
|
||||
selection,
|
||||
}
|
||||
|
||||
// All segment types get an extra segment handle,
|
||||
@ -825,8 +830,37 @@ function createLengthIndicator({
|
||||
lengthIndicatorText.innerText = roundOff(length).toString()
|
||||
const lengthIndicatorWrapper = document.createElement('div')
|
||||
|
||||
// Double click workflow
|
||||
lengthIndicatorWrapper.ondblclick = () => {
|
||||
const selection = lengthIndicatorGroup.parent?.userData.selection
|
||||
if (!selection) {
|
||||
console.error('Unable to dimension segment when clicking the label.')
|
||||
return
|
||||
}
|
||||
sceneInfra.modelingSend({
|
||||
type: 'Set selection',
|
||||
data: {
|
||||
selectionType: 'singleCodeCursor',
|
||||
selection: selection.graphSelections[0],
|
||||
},
|
||||
})
|
||||
|
||||
// Command Bar
|
||||
editorManager.commandBarSend({
|
||||
type: 'Find and select command',
|
||||
data: {
|
||||
name: 'Constrain length',
|
||||
groupId: 'modeling',
|
||||
argDefaultValues: {
|
||||
selection,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Style the elements
|
||||
lengthIndicatorWrapper.style.position = 'absolute'
|
||||
lengthIndicatorWrapper.style.pointerEvents = 'auto'
|
||||
lengthIndicatorWrapper.appendChild(lengthIndicatorText)
|
||||
const cssObject = new CSS2DObject(lengthIndicatorWrapper)
|
||||
cssObject.name = SEGMENT_LENGTH_LABEL_TEXT
|
||||
|
@ -109,6 +109,7 @@ function DisplayObj({
|
||||
setHasCursor(false)
|
||||
}
|
||||
}, [node.start, node.end, node.type])
|
||||
|
||||
return (
|
||||
<pre
|
||||
ref={ref}
|
||||
|
@ -1209,3 +1209,20 @@ function getWallOrCapPlaneCodeRef(
|
||||
range: planeCodeRef[0].range,
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get an artifact from a code source range
|
||||
*/
|
||||
export function getArtifactFromRange(
|
||||
range: SourceRange,
|
||||
artifactGraph: ArtifactGraph
|
||||
): Artifact | null {
|
||||
for (const artifact of artifactGraph.values()) {
|
||||
if ('codeRef' in artifact && artifact.codeRef) {
|
||||
const match =
|
||||
artifact?.codeRef.range[0] === range[0] &&
|
||||
artifact?.codeRef.range[1] === range[1]
|
||||
if (match) return artifact
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
Reference in New Issue
Block a user