Skip to content

Commit

Permalink
Fillet UI (#2718)
Browse files Browse the repository at this point in the history
* draft: fillet ast mod + test

* Kurt's rejig

* playwright

* update button enable logic

* remove fillet button in production build

* A snapshot a day keeps the bugs away! πŸ“·πŸ› (OS: ubuntu)

* trigger CI

* fix typo

* give a way to turn on fillets

---------

Co-authored-by: max-mrgrsk <[email protected]>
Co-authored-by: max-mrgrsk <[email protected]>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
  • Loading branch information
4 people authored Jul 15, 2024
1 parent 1852e61 commit a1df3d0
Show file tree
Hide file tree
Showing 28 changed files with 1,066 additions and 26 deletions.
81 changes: 81 additions & 0 deletions e2e/playwright/flow-tests.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3099,6 +3099,49 @@ const sketch002 = startSketchOn(extrude001, $seg01)
).not.toBeDisabled()
})

test('Fillet button states test', async ({ page }) => {
const u = await getUtils(page)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`const sketch001 = startSketchOn('XZ')
|> startProfileAt([-5, -5], %)
|> line([0, 10], %)
|> line([10, 0], %)
|> line([0, -10], %)
|> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%)`
)
})

await page.setViewportSize({ width: 1000, height: 500 })
await u.waitForAuthSkipAppStart()
await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.closeDebugPanel()

const selectSegment = () => page.getByText(`line([10, 0], %)`).click()
const selectClose = () => page.getByText(`close(%)`).click()
const clickEmpty = () => page.mouse.click(950, 100)

// expect fillet button without any bodies in the scene
await selectSegment()
await expect(page.getByRole('button', { name: 'Fillet' })).toBeDisabled()
await clickEmpty()
await expect(page.getByRole('button', { name: 'Fillet' })).toBeDisabled()

// test fillet button with the body in the scene
const codeToAdd = `${await u.codeLocator.allInnerTexts()}
const extrude001 = extrude(10, sketch001)`
await u.codeLocator.fill(codeToAdd)
await selectSegment()
await expect(page.getByRole('button', { name: 'Fillet' })).toBeEnabled()
await selectClose()
await expect(page.getByRole('button', { name: 'Fillet' })).toBeDisabled()
await clickEmpty()
await expect(page.getByRole('button', { name: 'Fillet' })).toBeEnabled()
})

const removeAfterFirstParenthesis = (inputString: string) => {
const index = inputString.indexOf('(')
if (index !== -1) {
Expand Down Expand Up @@ -3500,6 +3543,44 @@ test.describe('Command bar tests', () => {
`const extrude001 = extrude(${KCL_DEFAULT_LENGTH}, sketch001)`
)
})

test('Fillet from command bar', async ({ page }) => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`const sketch001 = startSketchOn('XY')
|> startProfileAt([-5, -5], %)
|> line([0, 10], %)
|> line([10, 0], %)
|> line([0, -10], %)
|> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%)
const extrude001 = extrude(-10, sketch001)`
)
})

const u = await getUtils(page)
await page.setViewportSize({ width: 1000, height: 500 })
await u.waitForAuthSkipAppStart()
await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.closeDebugPanel()

const selectSegment = () => page.getByText(`line([0, -10], %)`).click()

await selectSegment()
await page.waitForTimeout(100)
await page.getByRole('button', { name: 'Fillet' }).click()
await page.waitForTimeout(100)
await page.keyboard.press('Enter')
await page.waitForTimeout(100)
await page.keyboard.press('Enter')
await page.waitForTimeout(100)
await expect(page.locator('.cm-activeLine')).toContainText(
`fillet({ radius: ${KCL_DEFAULT_LENGTH}, tags: [seg01] }, %)`
)
})

test('Command bar can change a setting, and switch back and forth between arguments', async ({
page,
}) => {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
41 changes: 41 additions & 0 deletions src/Toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
canRectangleTool,
isEditingExistingSketch,
} from 'machines/modelingMachine'
import { DEV } from 'env'

export function Toolbar({
className = '',
Expand Down Expand Up @@ -118,6 +119,16 @@ export function Toolbar({
}),
{ enabled: !disableAllButtons, scopes: ['modeling'] }
)
const disableFillet = !state.can('Fillet') || disableAllButtons
useHotkeys(
'f',
() =>
commandBarSend({
type: 'Find and select command',
data: { name: 'Fillet', groupId: 'modeling' },
}),
{ enabled: !disableFillet, scopes: ['modeling'] }
)

function handleToolbarButtonsWheelEvent(ev: WheelEvent<HTMLSpanElement>) {
const span = toolbarButtonsRef.current
Expand Down Expand Up @@ -404,6 +415,36 @@ export function Toolbar({
</ActionButton>
</li>
)}
{state.matches('idle') && (DEV || (window as any)._enableFillet) && (
<li className="contents">
<ActionButton
className={buttonClassName}
Element="button"
onClick={() =>
commandBarSend({
type: 'Find and select command',
data: { name: 'Fillet', groupId: 'modeling' },
})
}
disabled={disableFillet}
title={disableFillet ? 'fillet' : "edge can't be filleted"}
iconStart={{
icon: 'fillet', // todo: add fillet icon
iconClassName,
bgClassName,
}}
>
Fillet
<Tooltip
delay={1250}
position="bottom"
className="!px-2 !text-xs"
>
Shortcut: F
</Tooltip>
</ActionButton>
</li>
)}
</ul>
</menu>
)
Expand Down
23 changes: 22 additions & 1 deletion src/components/CommandBar/CommandBarSelectionInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,25 @@ import { modelingMachine } from 'machines/modelingMachine'
import { useCallback, useEffect, useRef, useState } from 'react'
import { StateFrom } from 'xstate'

const semanticEntityNames = {
face: ['extrude-wall', 'start-cap', 'end-cap'],
edge: ['edge', 'line', 'arc'],
point: ['point', 'line-end', 'line-mid'],
}

function getSemanticSelectionType(selectionType: string[]) {
const semanticSelectionType = new Set()
selectionType.forEach((type) => {
Object.entries(semanticEntityNames).forEach(([entity, entityTypes]) => {
if (entityTypes.includes(type)) {
semanticSelectionType.add(entity)
}
})
})

return Array.from(semanticSelectionType)
}

const selectionSelector = (snapshot: StateFrom<typeof modelingMachine>) =>
snapshot.context.selectionRanges

Expand Down Expand Up @@ -85,7 +104,9 @@ function CommandBarSelectionInput({
>
{canSubmitSelection
? getSelectionTypeDisplayText(selection) + ' selected'
: `Please select ${arg.multiple ? 'one or more faces' : 'one face'}`}
: `Please select ${
arg.multiple ? 'one or more ' : 'one '
}${getSemanticSelectionType(arg.selectionTypes).join(' or ')}`}
<input
id="selection"
name="selection"
Expand Down
16 changes: 16 additions & 0 deletions src/components/CustomIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,22 @@ const CustomIconMap = {
/>
</svg>
),
fillet: (
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M8 5H5V15H15V12C15 8.13401 11.866 5 8 5ZM5 4H4V5V15V16H5H15H16V15V12C16 7.58172 12.4183 4 8 4H5Z"
fill="currentColor"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M4.5 3.5H5.5H8.5C12.9183 3.5 16.5 7.08172 16.5 11.5V14.5V15.5H16V12C16 7.58172 12.4182 4 7.99996 4H4.5V3.5Z"
fill="currentColor"
/>
</svg>
),
file: (
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
Expand Down
9 changes: 8 additions & 1 deletion src/components/ModelingMachineProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { applyConstraintAngleLength } from './Toolbar/setAngleLength'
import {
Selections,
canExtrudeSelection,
canFilletSelection,

Check warning on line 36 in src/components/ModelingMachineProvider.tsx

View workflow job for this annotation

GitHub Actions / playwright-ubuntu

'canFilletSelection' is defined but never used

Check warning on line 36 in src/components/ModelingMachineProvider.tsx

View workflow job for this annotation

GitHub Actions / playwright-macos

'canFilletSelection' is defined but never used

Check warning on line 36 in src/components/ModelingMachineProvider.tsx

View workflow job for this annotation

GitHub Actions / build-test-apps (macos-14)

'canFilletSelection' is defined but never used

Check warning on line 36 in src/components/ModelingMachineProvider.tsx

View workflow job for this annotation

GitHub Actions / build-test-apps (ubuntu-latest)

'canFilletSelection' is defined but never used

Check warning on line 36 in src/components/ModelingMachineProvider.tsx

View workflow job for this annotation

GitHub Actions / build-test-apps (windows-latest)

'canFilletSelection' is defined but never used
handleSelectionBatch,
isSelectionLastLine,
isRangeInbetweenCharacters,
Expand Down Expand Up @@ -72,6 +73,7 @@ import { uuidv4 } from 'lib/utils'
import { err, trap } from 'lib/trap'
import { useCommandsContext } from 'hooks/useCommandsContext'
import { modelingMachineEvent } from 'editor/manager'
import { hasValidFilletSelection } from 'lang/modifyAst/addFillet'

type MachineContext<T extends AnyStateMachine> = {
state: StateFrom<T>
Expand Down Expand Up @@ -444,6 +446,12 @@ export const ModelingMachineProvider = ({
if (selectionRanges.codeBasedSelections.length <= 0) return false
return true
},
'has valid fillet selection': ({ selectionRanges }) =>
hasValidFilletSelection({
selectionRanges,
ast: kclManager.ast,
code: codeManager.code,
}),
'Selection is on face': ({ selectionRanges }, { data }) => {
if (data?.forceNewSketch) return false
if (!isSingleCursorInPipe(selectionRanges, kclManager.ast))
Expand Down Expand Up @@ -494,7 +502,6 @@ export const ModelingMachineProvider = ({
kclManager.ast,
data.sketchPathToNode,
data.extrudePathToNode,
kclManager.programMemory,
data.cap
)
if (trap(sketched)) return Promise.reject(sketched)
Expand Down
14 changes: 3 additions & 11 deletions src/lang/modifyAst.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,6 @@ describe('testing sketchOnExtrudedFace', () => {
const ast = parse(code)
if (err(ast)) throw ast

const programMemory = await enginelessExecutor(ast)
const segmentSnippet = `line([9.7, 9.19], %)`
const segmentRange: [number, number] = [
code.indexOf(segmentSnippet),
Expand All @@ -321,8 +320,7 @@ describe('testing sketchOnExtrudedFace', () => {
const extruded = sketchOnExtrudedFace(
ast,
segmentPathToNode,
extrudePathToNode,
programMemory
extrudePathToNode
)
if (err(extruded)) throw extruded
const { modifiedAst } = extruded
Expand All @@ -345,7 +343,6 @@ const sketch001 = startSketchOn(part001, seg01)`)
|> extrude(5 + 7, %)`
const ast = parse(code)
if (err(ast)) throw ast
const programMemory = await enginelessExecutor(ast)
const segmentSnippet = `close(%)`
const segmentRange: [number, number] = [
code.indexOf(segmentSnippet),
Expand All @@ -362,8 +359,7 @@ const sketch001 = startSketchOn(part001, seg01)`)
const extruded = sketchOnExtrudedFace(
ast,
segmentPathToNode,
extrudePathToNode,
programMemory
extrudePathToNode
)
if (err(extruded)) throw extruded
const { modifiedAst } = extruded
Expand All @@ -386,7 +382,6 @@ const sketch001 = startSketchOn(part001, seg01)`)
|> extrude(5 + 7, %)`
const ast = parse(code)
if (err(ast)) throw ast
const programMemory = await enginelessExecutor(ast)
const sketchSnippet = `startProfileAt([3.58, 2.06], %)`
const sketchRange: [number, number] = [
code.indexOf(sketchSnippet),
Expand All @@ -404,7 +399,6 @@ const sketch001 = startSketchOn(part001, seg01)`)
ast,
sketchPathToNode,
extrudePathToNode,
programMemory,
'end'
)
if (err(extruded)) throw extruded
Expand Down Expand Up @@ -436,7 +430,6 @@ const sketch001 = startSketchOn(part001, 'END')`)
const part001 = extrude(5 + 7, sketch001)`
const ast = parse(code)
if (err(ast)) throw ast
const programMemory = await enginelessExecutor(ast)
const segmentSnippet = `line([4.99, -0.46], %)`
const segmentRange: [number, number] = [
code.indexOf(segmentSnippet),
Expand All @@ -453,8 +446,7 @@ const sketch001 = startSketchOn(part001, 'END')`)
const updatedAst = sketchOnExtrudedFace(
ast,
segmentPathToNode,
extrudePathToNode,
programMemory
extrudePathToNode
)
if (err(updatedAst)) throw updatedAst
const newCode = recast(updatedAst.modifiedAst)
Expand Down
2 changes: 0 additions & 2 deletions src/lang/modifyAst.ts
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,6 @@ export function sketchOnExtrudedFace(
node: Program,
sketchPathToNode: PathToNode,
extrudePathToNode: PathToNode,
programMemory: ProgramMemory,
cap: 'none' | 'start' | 'end' = 'none'
): { modifiedAst: Program; pathToNode: PathToNode } | Error {
let _node = { ...node }
Expand Down Expand Up @@ -388,7 +387,6 @@ export function sketchOnExtrudedFace(
if (cap === 'none') {
const __tag = addTagForSketchOnFace(
{
previousProgramMemory: programMemory,
pathToNode: sketchPathToNode,
node: _node,
},
Expand Down
Loading

0 comments on commit a1df3d0

Please sign in to comment.