From 83119b3b012581655249f549ab62d769c5458302 Mon Sep 17 00:00:00 2001 From: Kurt Hutten Irev-Dev Date: Wed, 3 Apr 2024 06:38:52 +1100 Subject: [PATCH 1/8] dynamic cursor depending on mouse scene state --- src/clientSideScene/ClientSideSceneComp.tsx | 20 ++++++++++++-- src/clientSideScene/sceneInfra.ts | 30 +++++++++++++++++++-- src/components/ModelingMachineProvider.tsx | 3 +++ src/machines/modelingMachine.ts | 21 ++++++++++++++- 4 files changed, 69 insertions(+), 5 deletions(-) diff --git a/src/clientSideScene/ClientSideSceneComp.tsx b/src/clientSideScene/ClientSideSceneComp.tsx index 4beec80e8b..b9d5c53c35 100644 --- a/src/clientSideScene/ClientSideSceneComp.tsx +++ b/src/clientSideScene/ClientSideSceneComp.tsx @@ -4,10 +4,11 @@ import { useModelingContext } from 'hooks/useModelingContext' import { cameraMouseDragGuards } from 'lib/cameraControls' import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext' import { useStore } from 'useStore' -import { DEBUG_SHOW_BOTH_SCENES } from './sceneInfra' +import { ARROWHEAD, DEBUG_SHOW_BOTH_SCENES } from './sceneInfra' import { ReactCameraProperties } from './CameraControls' import { throttle } from 'lib/utils' import { sceneInfra } from 'lib/singletons' +import { EXTRA_SEGMENT_HANDLE, getParentGroup } from './sceneEntities' function useShouldHideScene(): { hideClient: boolean; hideServer: boolean } { const [isCamMoving, setIsCamMoving] = useState(false) @@ -40,7 +41,7 @@ export const ClientSideScene = ({ >['settings']['context']['modeling']['mouseControls']['current'] }) => { const canvasRef = useRef(null) - const { state, send } = useModelingContext() + const { state, send, context } = useModelingContext() const { hideClient, hideServer } = useShouldHideScene() const { setHighlightRange } = useStore((s) => ({ setHighlightRange: s.setHighlightRange, @@ -76,9 +77,24 @@ export const ClientSideScene = ({ } }, []) + let cursor = 'default' + if (state.matches('Sketch')) { + if ( + context.mouseState.type === 'isHovering' && + getParentGroup(context.mouseState.on, [ARROWHEAD, EXTRA_SEGMENT_HANDLE]) + ) { + cursor = 'move' + } else if (context.mouseState.type === 'isDragging') { + cursor = 'grabbing' + } else { + cursor = 'crosshair' + } + } + return (
['send'] @@ -102,6 +103,7 @@ export class SceneInfra { _baseUnit: BaseUnit = 'mm' _baseUnitMultiplier = 1 extraSegmentTexture: Texture + lastMouseState: MouseState = { type: 'idle' } onDragStartCallback: (arg: OnDragCallbackArgs) => void = () => {} onDragEndCallback: (arg: OnDragCallbackArgs) => void = () => {} onDragCallback: (arg: OnDragCallbackArgs) => void = () => {} @@ -338,8 +340,6 @@ export class SceneInfra { planeIntersectPoint.twoD && planeIntersectPoint.threeD ) { - // // console.log('onDrag', this.selected) - this.onDragCallback({ mouseEvent, intersectionPoint: { @@ -349,6 +349,10 @@ export class SceneInfra { intersects, selected: this.selected.object, }) + this.updateMouseState({ + type: 'isDragging', + on: this.selected.object, + }) } } else if ( planeIntersectPoint && @@ -373,6 +377,7 @@ export class SceneInfra { selected: this.hoveredObject, mouseEvent: mouseEvent, }) + if (!this.selected) this.updateMouseState({ type: 'idle' }) } this.hoveredObject = firstIntersectObject this.onMouseEnter({ @@ -380,6 +385,11 @@ export class SceneInfra { dragSelected: this.selected?.object, mouseEvent: mouseEvent, }) + if (!this.selected) + this.updateMouseState({ + type: 'isHovering', + on: this.hoveredObject, + }) } } else { if (this.hoveredObject) { @@ -388,6 +398,7 @@ export class SceneInfra { dragSelected: this.selected?.object, mouseEvent: mouseEvent, }) + if (!this.selected) this.updateMouseState({ type: 'idle' }) this.hoveredObject = null } } @@ -445,6 +456,11 @@ export class SceneInfra { (a, b) => a.distance - b.distance ) } + updateMouseState(mouseState: MouseState) { + if (this.lastMouseState.type === mouseState.type) return + this.lastMouseState = mouseState + this.modelingSend({ type: 'Set mouse state', data: mouseState }) + } onMouseDown = (event: MouseEvent) => { this.currentMouseVector.x = (event.clientX / window.innerWidth) * 2 - 1 @@ -484,6 +500,16 @@ export class SceneInfra { mouseEvent, selected: this.selected as any, }) + if (intersects.length) { + this.updateMouseState({ + type: 'isHovering', + on: intersects[0].object, + }) + } else { + this.updateMouseState({ + type: 'idle', + }) + } } else if (planeIntersectPoint?.twoD && planeIntersectPoint?.threeD) { // fire onClick event as there was no drags this.onClickCallback({ diff --git a/src/components/ModelingMachineProvider.tsx b/src/components/ModelingMachineProvider.tsx index ef7a8a5e9c..ec5f327295 100644 --- a/src/components/ModelingMachineProvider.tsx +++ b/src/components/ModelingMachineProvider.tsx @@ -112,6 +112,9 @@ export const ModelingMachineProvider = ({ kclManager.executeAst() } }, + 'Set mouse state': assign({ + mouseState: (_, event) => event.data, + }), '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 const setSelections = event.data diff --git a/src/machines/modelingMachine.ts b/src/machines/modelingMachine.ts index 97dd7c36ae..3bcc8fd4d9 100644 --- a/src/machines/modelingMachine.ts +++ b/src/machines/modelingMachine.ts @@ -64,6 +64,19 @@ export type SetSelections = selection: Selections } +export type MouseState = + | { + type: 'idle' + } + | { + type: 'isHovering' + on: any + } + | { + type: 'isDragging' + on: any + } + export interface SketchDetails { sketchPathToNode: PathToNode zAxis: [number, number, number] @@ -128,12 +141,13 @@ export type ModelingMachineEvent = type: 'done.invoke.animate-to-face' | 'done.invoke.animate-to-sketch' data: SketchDetails } + | { type: 'Set mouse state'; data: MouseState } export type MoveDesc = { line: number; snippet: string } export const modelingMachine = createMachine( { - /** @xstate-layout N4IgpgJg5mDOIC5QFkD2EwBsCWA7KAxAMICGuAxlgNoAMAuoqAA6qzYAu2qujIAHogC0ANgCcARgB0NcQHYAHKIBMw8QGY1ogKxKANCACeiWUvmT5SraNE15a4QBZxW2QF9X+tBhz4CAZTB2AAJYLDByTm5aBiQQFjZInliBBEFtWUlxGlEnWWVZNQc1fSMEDSl1NXlVewcirWE1d090LDwoSWwITDACAFFcdjAAJxCAa0DyAAto3niOLiTQFMEVDPEVUUd5DfFxYVkHEsQlHMkioqUnNWzq0WaQLzb8Tu7egaHR2An2aapxGLMVgLbi8FZXGjnfYyLS2G7yGiyY4IBw0JSSfLCLQbYQ7Kr7B5PHwdLo9fp8djDACuGFmsXmiTBQi0LkkpxoDW0Di0O2Re1hbOqim0NAcOSchNaxNeZL6fBYw3YdKBCUWTNSpjMpghSiU4jF3PkyNksikBy0hSxCKUhy0ku87Ukfh+02IZEomGdkxm9DmwMZyUQe1EZgcKgOGxoaj1uL5ShkkgtciFzgOOXtzw6Xt+UydLqmAEk3gRkCQJiEwFAALZgQZBABuI045BImGVcX9asDCHUUcTaMRthouNhWj5RTUklNNxkouEwlF9w8jyljuz0zz3qLZNL5dC1drwSmqGG2AAXtx2K32wyu8sg6ZhBibRYLGoWTYjYYg+UMTyDqadTyLIBwZtK665hB269EQ3CwJSJB4EEx6nhegytkEEDYPB7pgDenagt2OJPvYzjRukhxXMiVz7OcuIOLIVgmKIhQOGBa75puObQcQcEIUhjaKtgLaYJh2FXhQeG+vSBFLPwD47GyJiIgxjQ2Ao1GnJOLGmgupxZMB7EvBBXHTDxsG4PBwyIbgQQAIIAEJ+EEAAa+GqoR949qcGSMQcVQck4ziiNRoiMZI9hhSyFphdoRlZpxUHFhZVk2fZTlBAAmu5IJySkGxhYmNTyA0VQMSGyJqFkoiZFUOimrqDRaGxy5Ehx3qmYWyV8dZSFkFAPQ5QGXnqCyU5RhycizmiwjUfVkgRiy0ayMOerxZ1nXmT1aU9Pg7A+oCHYeXlP5igt8gOHYjXYlUs3fggKiaJkb4sYaVrrSZSVkil-G2UwIz-bgWHkFSmAkKMWE4ZJQ13vJ3mouY4gle+OgOPRej3aY761aYBRKFUmwfYl+ZbZZv3ISe56Xq2mAGEErbYFAuAw55cMbOFcgmrYaMWKcIX3WRT4rfIb40WV8hEx1X0wdtAlNsJNN0wzTMsyd3kSFOOhZI9yhI0iAuOE+NBoiaThbAiIuSzmm3dWTvW2bAuAkEwQTsKgrmq+q6iWImdhRnqs7CCo1GrQtt1hsGYgtS0DrGcTW626lSGO87rvu9l0kqrlXvRloEXaM1thWPk+ulDGGRbFN+pVaYLhWxu0u8XbaVgAAjlSGG7VA+2e0RNx53YqJoq+iImHyjGQhdy0sitmgcvXkEk4n5NMODNPUJnR3Z33T2FEjzW6TRfLpOcaPqBP3JNK1q5x1LS-fbLtnDGAVaoI2QTkI-7CwL3I0qJCLF9h5FRGIHY-NSj7ykGGEM2gchiFHgvG2ZIABKYBBBgD4OEKkQxf5s3sHnbkOh3wHBKnkO6pQQwZFnKab2-klCIMbn0du2AXYABk8BgDTqgNsm9bys3yp+cwOhgI3BAlVOQyISp52UGiTm9ETDCAYffd4zCXYSRgIMbAGFwbkDTrglIeoETjUugfBEWJwFBg2OiJGzgdg+RUBLa+scEodTsgAd0QkeSmaEryiUhhJSgQQ8AADNUAEAgNwMAnRcD1lQBMSQMB2CCBQlTdCmBBAhNQPok4VUhZYkaI+UwMhqJ1EhCoFwIZcSiMcTHTMG13GeIpqhamfjxK4SCbgUJBARjDBPJIJgYN2ChOGFWBJgRkneJaRkzpWTeGyXVPjOQ5wNCNDqLiPYGgSlonOBaFw-4rSWEQQ0jgDZ5YiTElDQJmTwmROibE+JiTBCCWbK2aZoTskPWjA4HZs9Cg2BkI0aiNxvmal1CBNG1h7BHI8Sc55CtWmXM4dcnpfSBkkCGSeUZjy4UiTebMw6fC1b4x9hsMUvNKmOE0kHRMCgXB5FkeIaFjTHLORch0rpETcBRLwPcqJjySAACNYCCD4Hij5xKaq2CsRacFUYjiYxDOiJamhxBwKAjUlczj6kwuCCy1y7KwkouGP0wZwysXjMFcK0VmTxXkU1lVYc041CAVCvYKch9qj7xWnaJxdSTLHN1RlTKBqblcruXEvlFqhWCAMGKuZx0FnRjMAcMU9KtYVXuvCCuwZ-7m0Yj62p4FOIBvSs5YNyLhi9ONWijFIyxlJMtTGuNBL5ndglRFHmC4qgSCxJVJG3zLqPRNFiVVhQmUnP6j0ENnLuUxIjfWwQk60E2vjdvLy7ag5Rh5ATU25CTh0o7YUEC85zZLkLe1a2Jal0hqNSa9FZqF1LubX6BNbbfxog0NiK4zqyJzWdYmcp3JwWFA1W1W+l6dVBC7vtadtyeXzsedBqYz6ZKvvXctTW+w5A+RmsUTG3rzggVOLjZVBbNV+uLZBpDN7K2otNZihdSGUNZ2GnDYloZVU8gKgVPdD15yTkRM1RwMCmLjuCP9YYgNgag3BhcgJSKZmhtnbyhdEmpPCRk8MQQ-jcLMa3qxgxNo842kYgxW0sJeOmG5FOC6dQ9SVAYmJoIanazSbBhDNpkkaNVrvbW81SSXNAw0+57TnnKB6cJQsozSlTOmxZMOaieRfK2Yjg5twvqi0dXYVyrhmB+iqNdv1Q8WjRI6L0augzJwFBPgYjXVE7NVXyooYVC6BwCn4wjmRsDLjrbZc4W7bhkgCy4A4AQcVVwarOFNrsYWNpjQJhHRIQhWGqiIL67lobI32BjYBC+tdbGrPmF1FGbQIHlC8byDVYCI6zOIl1GtjhG2ABy7sAAKqA8DfwIHZCAEAQhXkVM5j7gxxUATZFcEWlhYQixNMiXEV36omCsOU9MGWL0bnWwNzAkgXtBHe592AbpJI8JbWhtmnqIrYgXFrECFgmvGD1BibI+xIfzguul894GNzDdGx87WZgERijWEUzZAtLCThFsOGEhwi6KLR1z3MPPtv-FJ-t-Kw4QVZHZqZiwY4BY10yCGaM+xURVS6zfHrG4AAqRXNHaOGLot2+WqQsKCJj1A3DQcNE1sbbIiJWKFGRFsdYJV7N6jWRYRBVIgbuxwoqCCAB5XASnw3xLsn4K3gho8RMEHH9gifmYVdhvlDQZh6oqv1PUWwyIeQANUJ+WrdhnULyCLgd2wSSCUH8GECImEwAd9BuJsGXKPmrD2M9HIzrDjVEONoOHKhEYdeddYcFZ7yPSjINgKs6L2hp2c8P3oM7U9RM39voYgg3aCA75QD5LIKgIgUKKY2x3S6ICDmYGuGhh5hUuqBi3khT8d98A98MFxJd9vhvQU94N4lADz9L8ICcwPkg484ZobQQxnAigx5M0kYFp-JFBcRFAGJHFlw28MB4BYhus9tKtUgChJVkxztKhtAMYIERZzBZ8NBTRB4EF5cSQ3gqDi8hBtgioksyoeQGJJFFILQpUkx8YZA19utOp+D+FEAQxJ5FxhcERRcy4QIIpZ8kYDgjMZUlEE4eglC1Z9RnAFogE0RUQZdA8xd9RExmp4xVAGJUY-8tV-VIMUkfEMIdMvNMkzCvZJcpw9IZA7APwqgSkNhNYLAQIkYbh8gnMcU-CwsFNQkgiiJCDCNlB7BzE9g0ZNIVpllTRORNCkcnM9U2VAjUM1cgwbACEP13Chc6hQpsRzAxB4idBKEwpKig0DVMiRobBvl2csQhcVp8Y9dSh4Q85GhkZxFykownNr0aiWMBCex1IMQhd5wtZ3w8My5ui2R7A7A9hw9uQnNqNVj9N1jVVtkTAXxCC9QbBmCTgsQMh4wxRGhR0TMPCKNXFINAs3NZN-CrkZlBjycxBMgpszcfjX8HprQcZB4T1VACgHscssdwSDF+R85-5qgYwe04dtl3wbQGIgIqpUdOdLdcx3dBsldMSTh9hJxNBcSg59gCT7oGoaUWJ4xnBHwLo0T+sPdsc28RlWx6SHpYQaoyEWRjsqpuR6cEATApAbAe1Wd5EBTns3tgdv5xSrgsQFoP0Gp-4LsLAFochbBgIZAIU5dKSNo6TajqCshTQMRDYGIsM9QpiHwEwkxqsdgGhgFEEbd8Bit7dHdUBdSmJpAJASpzS8SqIBY7tzoTdUQp4x0eCNps9Y8Ad898wk9xSq4hEGJbBGJqgGgFSGgnxgIxRfcVoFwOd190cphW929O8wBxTVgEYrpzRDhhZuRkR5T+wrBjYnS8hUZ1pYDd83Z98yA2yHSbjGgMQQJhj0hIxeMg4jYqhrtmo-ZDJ0yJzgCpzQD4JwD8x8zCo-I3jZEihVUXj4TIR5xbBniUz393B3AgA */ + /** @xstate-layout N4IgpgJg5mDOIC5QFkD2EwBsCWA7KAxAMICGuAxlgNoAMAuoqAA6qzYAu2qujIAHogC0ANgCcARgB0NcQHYAHKIBMw8QGY1ogKxKANCACeiWUvmT5SraNE15a4QBZxW2QF9X+tBhz4CAZTB2AAJYLDByTm5aBiQQFjZInliBBEFtWUlxGlEnWWVZNQc1fSMEDSl1NXlVewcirWE1d090LDxCAODYdgAnMBIAWyDyAFce2FQe6N54ji4k0BSaEsQaZpAvNvxJbAhMMAIAUVx2MB6QgGtA8gALadjZxN4UwRUM8RVRR3kP8XFhWQOFYIJQ5SRFIpKJxqbLVUTrTY+KA7PYHY6nc6wK7sW5UcQxZisObcZ5CKE0cH-GRaWww+Q0WTAhw0JSSfLCLQfYQ-Kr-BGtJEo-ZHPi9EYYe6EhLzUmpLQuSSgmgNbQOLQ-YF-GmK6qKbQ0Bw5Jz87ztIVovgsHrsSVxIlPZJk+RmUzkpRKcSGtXyYGyWRSAFaQoc+lKQFaE1bZF+bG3YhkSiYGPXO70Gb2mWOhB-DTg5TCDm-bnqTXiGySTkOeQKDSKaoOSOC5M4m6SZu3ACSqIIyBIVxCYCgAzAJyCADczpxyCRMLbHpnFogPlUK9yaI4TEHnJqHO7JGJhNlLGIJOJ5I2ze3W1eu8Le-3QkOR8EbpNsAAvbjsGdzjMkrMfB6bKiFU7rOMy8pAoYS5qEoFI5HI3IFj8djCBe2xXm2sY3LeBxENw3Q9CQeBBK+PQfl+M5BBA2DdAmYC-tK-6LtmcFSLusg6NysjCHBjLQSCEHgpyDSAl8ULqOh0bYVhKa4cQBG9MRuDjpO2DTpg1G0d+FAMWmDx-gs-BLh6wiSLW666koagmMUAnuhYbJwZYZ6epoDYeBsAqXjJN7dvhuCEcpQQAIIAEJ+EEAAajHEkZKTLqyFhhmoZabvSUGlKCjjmTo8gOLI66pTI56eYiPkprJLbyQFQUkeFkUAJqxQ6LGJfuKV5PKYh1HZpQwqIZhFmejjqrZUlVbck04f5ilESRZBQPsLULsZrHljxNhqqoOQAsCLlmRyDiOAVIHKKVLSmhhvnYTVc3Bfs+DsKmBJ2kx8UmflkicbYKhyPYNCwftvFDUd+WDWWHITZhfnCrVSkkUwZxI7gNGjJgJDnDRdG6StzFrX8nHmPlOhGqlVb8VlFgOJkzhfAVqguGhZXeddlWw3h90kWRFEnDOmAGEEM7YFAuB4x9rFZIqRSFdZ1Q9ZlS46Fo+4SBIDPHRIF1eVd0ns7ds2BQjKkTta6n84Lwui+LsqAWZKHZByTN2HoAn-IUbLyOqHImDIzhuCzuvTdNd1G-NKmwLgJBMEE7CoNFNsASoFKODYydljo-r7cqAYegUtQwjI0M3XJht1RHUcx3HQTNfpUpxbbyfgozhR+nYyiu1lzhmUaeSgloar5MX+ul3DXMqWAACOIxUY9UDPYnbXkuY1jWACx0D2emoFKI5gqPYhUgWIJjDy2Idl8bQRMJj-PUHXb0N0ngLggy+XVK3ypaJqu3gqC7ppzWbkp8pocwUmHYKfQBioAnMMce7BYCLwJhnYCPF86WDqI4TU+UKROFBNWAqLJPQeUulGYOoCABKYBBBgD4OEEYpxEEJULhWD0-8rCFSKKIYEogibWCqCyL2NBAbVmAdeA2wpDjT2wDHAAMngMAsdUCoFnPfec+MEr5TUGyM88trAFR4sCfKNMbAaCPBIP0ORRHnwkVIqui1nzYCopjcgijGGIA9M4b6hU34nkSqWP4mRHAAldMqQEAcSFNhkiFAA7sRF8b5Px800tjHSlAgh4AAGaoAIBAbgYAdi4DHKgK4kgYDsEEDzRJ35MCCEyagNxIIXLmFSrxAEPwVBf3sruXeUJnRpyKl7KxMS4mkQSZRZJ2l6LpNwFkggZweiTEkEwDG7Ask9AGKUwIFSxlJNqTM+pqjDKyndDoPM4k7DVBcAY+ymh2L2ALAUOsihiE61IZhYZHBVJmw0lpHGaS6k5LyQUopJSymCFNlOGceyskNJObvHQMIwzMjfuufaoItFhnUGWOQgMhHMwiRVM+HzggQvNhMv5CiAXzMWcskgqzJgbLBaSjS0KDmvTURLd0h5Mg2B4bxOQHwfT2SaQ0f4PV0H-G1uVNmRLYmfIatFaZszcm4HyXgEF+SwUkAAEawEEHwVlsKVA009CYMsoIqwAkpu4nhUggzfGDDw+U4TXmRMqsS0KEVFVUp6AsnoSyVlrMZVsnVeqDV1KNTlH4Eg8WpTsC4faygVacQKmxJw1ZARDLlcEBVjUlXZJVWqwpxTNUht1YIAwhrDnvWOfvb6zIeGgkKgWKEwIYQ8RXjSRCbFqZZpGbm-NczfU0sDQyzZ5TQ0Vqreyo5WYuU01wV7IoDJeLaDbf9ZuLg-7OhpAaPtnzFr7EHYW4FJbx2CEPVQiN1bH4sXnfud+CKZDWS4fZBoZlYIcmLMoNe+7giXsHdS-1tL6XrPPZe6d6Ya1zpUGZWwIE1T-Dzl8faXEKyOxsqYHi8o-1BDns9Y9QL1VnrBfhm4kGDLQbvSoJKiE-gegHjYYQwMwSDyqJw50EFcNkcA8O4Do6wOkZHPPcj16Z1UbWlyrRVZnU6GyNcrKHJWTKi9g0TkSoXnSr1rKkZSMegozRiMDGWNJm6UI6q09oKtl6YM+pIzmNBApPohR+urVJMegpIUNQm8CyaA4ftOwNNUFBnsPcoMUrWbaamh6mzI5DPGd+akyl+yh1+oDXSoN57Yuozs8ZxzpnKAuYfm5lIYFPP1CcL5nhBp9oKDMsFjQjQCzhasXI1VijlFHFsbHexJxHGaWca4m9JX3FmorLcuQIE-h2GtQgQa9s8ED0BMEiwrX5EdcwJIDsuAOAEFhWeGm7obLefUJBWbYgU7ebxQyQ0cEIyBzeTJNrCi47KK2zt9ge38RQdve5ssxN6QaDVBoBNAkFBmC9l8dcFqBEuq08HZ7G3JAADl44AAVUB4HgQQEKEAIAhG-NaK+mOTiwtUKyJU1YgkgR0MCNpzTvZODpi2tb7XXubdR0EDHWPYDxl0io8Tv2Ep5DMrkKwEh7Cmt9FLRQXLAaGmsJ6Kx23dsNK+Fo6sR51zHUNICTUUIkpNZAvJzQKhlcfa+4Lkbc3rCKh4kWAopgciahhBUH40J3a8SUFYgAKr1zgTieguLjl1kY0igiI-Z7CqwUgfiHhZIrmwQrSjaDMpKxFBQ-RiSsSMVG8c6LWivAAeVwICizxGSkhT8D7wQufcmCAL+wYvYthurSYSuTOE3eo0mT4gdU8Edq2AKlUDQcPIvTSCLgeOGSSCUH8GECI1EwAz6M8EWlqqGmvACWeHINlATVDEp00orTzDLhltYHihoJpkGwAMOl7RFFXwxqqsvRaNWSBv3f04gg46CBn5QBpeUN3V+A0IRd0BkOnUwcyZcRFRQffCLIOT-e-fAR-GhbSB-LEFMV-SzfJJA7-X-TAlsBpXiFWFkXiPIH4AeTDddMwB5KoL4PpAqUqTyKfDAeAWILTH7a3QQHeaQOQWXGoTQWnN2TkcwfvHFKEKwGQTTcfXYfYLgtvIQb4VcPIR5b0AqQxH4cbWwZwVKayGQeEB7N1FsBQ9RRACQFWTXZQbXVOPXG5XebzekSbdUduTiKxDmUwiWU7FOCwA8WCb2XvViQGcbEwPlbxONXDSpcZRLKZOpTw22SgveHaFwAeFTPqdxZkKQQEdQK1IqX9IwwlaLbNL5SFclJLfNeIgCCweFNUfQq5FwV9LKSwXeXcFkGTQGAESxAomVIo-tL1KKCoyjIXJcbBZuQLRwQGegxNZkMQ0wIMZUONAEXDAdOIoY63M8TQbRWoTjAeZ0NtG7DqJDY6bzdIb3boqLVsD1ADVY1zRQ7MTRPgriA0TQH4OwrKTkF0MsDuE6TiM4glHoy44onjG44rO4jYjIcHBQUwQ8I6WbY1NPZ0ZUAqf4dUAqXDbLeLTGGIszEEjlBIg0TIV49BY6FyRWEEPICoOmP6H9A3VnF7JRTASou9ZUHBb2FkVI7uYEGPcyRwxoGQGyOkpHFXdgJkyTWEYSaodkzIhoX0GQVcCSf4e3TicQQU9nSQKfdZGcUU0rOoGmaodBcnKkHhaXCkWXZOQoVeJXc4hHdbNUznbnE4dg24swwSIRfcbkewSsWo46X0f0fcP0M8FkKEP0Roc3DgbUpcIRDIXFRwLIEXPIMkv4csSsasOweg+sX3f3frIWIPRRCMkEIMVkf2L2DQMMWwPaN2dcAMDcbzQ8S-FU60zCOvfPQnJvbCEvfMz3JyBkMggMviLk+UMQvICws6dQBAx7FMSfafWfMAfM14GYl2QMMJIfI-RANUGmGkKQmQBkLqKEa-HbL-B-audfWctYsExoNkTaA0dID4VFASE-YRKnXYukMfRAg85AqAVAvgdAlAwg24Tsnhb6d9FwQhIoc1ALFOQ8RQNo8s0wdwdwIAA */ id: 'Modeling', tsTypes: {} as import('./modelingMachine.typegen').Typegen0, @@ -157,6 +171,7 @@ export const modelingMachine = createMachine( sketchPlaneId: '' as string, sketchEnginePathId: '' as string, moveDescs: [] as MoveDesc[], + mouseState: { type: 'idle' } as MouseState, }, schema: { @@ -535,6 +550,10 @@ export const modelingMachine = createMachine( internal: true, actions: 'Set selection', }, + 'Set mouse state': { + internal: true, + actions: 'Set mouse state', + }, }, }, { From 957c086bd19c3a0dd8209e54ce7e420a67216e8b Mon Sep 17 00:00:00 2001 From: Kurt Hutten Irev-Dev Date: Wed, 3 Apr 2024 15:11:32 +1100 Subject: [PATCH 2/8] hover stuff --- src/clientSideScene/sceneEntities.ts | 220 ++++++++++++++++++--------- src/clientSideScene/sceneInfra.ts | 18 +-- src/clientSideScene/segments.ts | 6 +- 3 files changed, 157 insertions(+), 87 deletions(-) diff --git a/src/clientSideScene/sceneEntities.ts b/src/clientSideScene/sceneEntities.ts index 2ff83a25a1..e08d076b4a 100644 --- a/src/clientSideScene/sceneEntities.ts +++ b/src/clientSideScene/sceneEntities.ts @@ -98,8 +98,9 @@ export const TANGENTIAL_ARC_TO__SEGMENT_DASH = 'tangential-arc-to-segment-body-dashed' export const TANGENTIAL_ARC_TO_SEGMENT = 'tangential-arc-to-segment' export const TANGENTIAL_ARC_TO_SEGMENT_BODY = 'tangential-arc-to-segment-body' -export const MIN_SEGMENT_LENGTH = 60 // in pixels export const SEGMENT_WIDTH_PX = 1.6 +export const HIDE_SEGMENT_LENGTH = 60 // in pixels +export const HIDE_HOVER_SEGMENT_LENGTH = 35 // in pixels // This singleton Class is responsible for all of the things the user sees and interacts with. // That mostly mean sketch elements. @@ -563,7 +564,7 @@ export class SceneEntities { }, }) }, - ...mouseEnterLeaveCallbacks(), + ...this.mouseEnterLeaveCallbacks(), }) } setupSketchIdleCallbacks = ({ @@ -685,7 +686,7 @@ export class SceneEntities { if (!event) return sceneInfra.modelingSend(event) }, - ...mouseEnterLeaveCallbacks(), + ...this.mouseEnterLeaveCallbacks(), }) } prepareTruncatedMemoryAndAst = ( @@ -882,7 +883,16 @@ export class SceneEntities { }) const pxLength = arcInfo.arcLength / scale - const shouldHide = pxLength < MIN_SEGMENT_LENGTH + const shouldHideIdle = pxLength < HIDE_SEGMENT_LENGTH + const shouldHideHover = pxLength < HIDE_HOVER_SEGMENT_LENGTH + + const hoveredParent = + sceneInfra.hoveredObject && + getParentGroup(sceneInfra.hoveredObject, [TANGENTIAL_ARC_TO_SEGMENT]) + let isHandlesVisible = !shouldHideIdle + if (hoveredParent && hoveredParent?.uuid === group?.uuid) { + isHandlesVisible = !shouldHideHover + } if (arrowGroup) { arrowGroup.position.set(to[0], to[1], 0) @@ -894,7 +904,7 @@ export class SceneEntities { new Vector3(Math.cos(arrowheadAngle), Math.sin(arrowheadAngle), 0) ) arrowGroup.scale.set(scale, scale, scale) - arrowGroup.visible = !shouldHide + arrowGroup.visible = isHandlesVisible } if (extraSegmentGroup) { @@ -913,7 +923,7 @@ export class SceneEntities { 0 ) extraSegmentGroup.scale.set(scale, scale, scale) - extraSegmentGroup.visible = !shouldHide + extraSegmentGroup.visible = isHandlesVisible } const tangentialArcToSegmentBody = group.children.find( @@ -970,7 +980,19 @@ export class SceneEntities { ) const pxLength = length / scale - const shouldHide = pxLength < MIN_SEGMENT_LENGTH + const shouldHideIdle = pxLength < HIDE_SEGMENT_LENGTH + const shouldHideHover = pxLength < HIDE_HOVER_SEGMENT_LENGTH + + const hoveredParent = + sceneInfra.hoveredObject && + getParentGroup(sceneInfra.hoveredObject, [STRAIGHT_SEGMENT]) + let isHandlesVisible = !shouldHideIdle + if (hoveredParent && hoveredParent?.uuid === group?.uuid) { + isHandlesVisible = !shouldHideHover + } + if (isHandlesVisible) { + console.log('hoverGuy', hoveredParent, sceneInfra.hoveredObject, group) + } if (arrowGroup) { arrowGroup.position.set(to[0], to[1], 0) @@ -983,7 +1005,7 @@ export class SceneEntities { .normalize() arrowGroup.quaternion.setFromUnitVectors(new Vector3(0, 1, 0), dir) arrowGroup.scale.set(scale, scale, scale) - arrowGroup.visible = !shouldHide + arrowGroup.visible = isHandlesVisible } const extraSegmentGroup = group.getObjectByName(EXTRA_SEGMENT_HANDLE) @@ -997,7 +1019,7 @@ export class SceneEntities { 0 ) extraSegmentGroup.scale.set(scale, scale, scale) - extraSegmentGroup.visible = !shouldHide + extraSegmentGroup.visible = isHandlesVisible } const straightSegmentBody = group.children.find( @@ -1175,6 +1197,120 @@ export class SceneEntities { }, }) } + mouseEnterLeaveCallbacks() { + return { + onMouseEnter: ({ selected, dragSelected }: OnMouseEnterLeaveArgs) => { + if ([X_AXIS, Y_AXIS].includes(selected?.userData?.type)) { + const obj = selected as Mesh + const mat = obj.material as MeshBasicMaterial + mat.color.set(obj.userData.baseColor) + mat.color.offsetHSL(0, 0, 0.5) + } + const parent = getParentGroup(selected, [ + STRAIGHT_SEGMENT, + TANGENTIAL_ARC_TO_SEGMENT, + PROFILE_START, + ]) + if (parent?.userData?.pathToNode) { + const updatedAst = parse(recast(kclManager.ast)) + const node = getNodeFromPath( + updatedAst, + parent.userData.pathToNode, + 'CallExpression' + ).node + sceneInfra.highlightCallback([node.start, node.end]) + const yellow = 0xffff00 + colorSegment(selected, yellow) + const extraSegmentGroup = parent.getObjectByName(EXTRA_SEGMENT_HANDLE) + if (extraSegmentGroup) { + extraSegmentGroup.traverse((child) => { + if (child instanceof Points || child instanceof Mesh) { + child.material.opacity = dragSelected ? 0 : 1 + } + }) + } + const orthoFactor = orthoScale(sceneInfra.camControls.camera) + + const factor = + (sceneInfra.camControls.camera instanceof OrthographicCamera + ? orthoFactor + : perspScale(sceneInfra.camControls.camera, parent)) / + sceneInfra._baseUnitMultiplier + if (parent.name === STRAIGHT_SEGMENT) { + this.updateStraightSegment({ + from: parent.userData.from, + to: parent.userData.to, + group: parent, + scale: factor, + }) + } else if (parent.name === TANGENTIAL_ARC_TO_SEGMENT) { + this.updateTangentialArcToSegment({ + prevSegment: parent.userData.prevSegment, + from: parent.userData.from, + to: parent.userData.to, + group: parent, + scale: factor, + }) + } + return + } + sceneInfra.highlightCallback([0, 0]) + }, + onMouseLeave: ({ selected, ...rest }: OnMouseEnterLeaveArgs) => { + sceneInfra.highlightCallback([0, 0]) + const parent = getParentGroup(selected, [ + STRAIGHT_SEGMENT, + TANGENTIAL_ARC_TO_SEGMENT, + PROFILE_START, + ]) + console.log('onMouseLeave', parent, selected, rest) + if (parent) { + const orthoFactor = orthoScale(sceneInfra.camControls.camera) + + const factor = + (sceneInfra.camControls.camera instanceof OrthographicCamera + ? orthoFactor + : perspScale(sceneInfra.camControls.camera, parent)) / + sceneInfra._baseUnitMultiplier + if (parent.name === STRAIGHT_SEGMENT) { + this.updateStraightSegment({ + from: parent.userData.from, + to: parent.userData.to, + group: parent, + scale: factor, + }) + } else if (parent.name === TANGENTIAL_ARC_TO_SEGMENT) { + this.updateTangentialArcToSegment({ + prevSegment: parent.userData.prevSegment, + from: parent.userData.from, + to: parent.userData.to, + group: parent, + scale: factor, + }) + } + } + const isSelected = parent?.userData?.isSelected + colorSegment( + selected, + isSelected ? 0x0000ff : parent?.userData?.baseColor || 0xffffff + ) + const extraSegmentGroup = parent?.getObjectByName(EXTRA_SEGMENT_HANDLE) + if (extraSegmentGroup) { + extraSegmentGroup.traverse((child) => { + if (child instanceof Points || child instanceof Mesh) { + child.material.opacity = 0 + } + }) + } + if ([X_AXIS, Y_AXIS].includes(selected?.userData?.type)) { + const obj = selected as Mesh + const mat = obj.material as MeshBasicMaterial + mat.color.set(obj.userData.baseColor) + if (obj.userData.isSelected) mat.color.offsetHSL(0, 0, 0.2) + } + }, + } + } } export type DefaultPlaneStr = 'XY' | 'XZ' | 'YZ' | '-XY' | '-XZ' | '-YZ' @@ -1417,69 +1553,3 @@ function massageFormats(a: any): Vector3 { ? new Vector3(a[0], a[1], a[2]) : new Vector3(a.x, a.y, a.z) } - -function mouseEnterLeaveCallbacks() { - return { - onMouseEnter: ({ selected, dragSelected }: OnMouseEnterLeaveArgs) => { - if ([X_AXIS, Y_AXIS].includes(selected?.userData?.type)) { - const obj = selected as Mesh - const mat = obj.material as MeshBasicMaterial - mat.color.set(obj.userData.baseColor) - mat.color.offsetHSL(0, 0, 0.5) - } - const parent = getParentGroup(selected, [ - STRAIGHT_SEGMENT, - TANGENTIAL_ARC_TO_SEGMENT, - PROFILE_START, - ]) - if (parent?.userData?.pathToNode) { - const updatedAst = parse(recast(kclManager.ast)) - const node = getNodeFromPath( - updatedAst, - parent.userData.pathToNode, - 'CallExpression' - ).node - sceneInfra.highlightCallback([node.start, node.end]) - const yellow = 0xffff00 - colorSegment(selected, yellow) - const extraSegmentGroup = parent.getObjectByName(EXTRA_SEGMENT_HANDLE) - if (extraSegmentGroup) { - extraSegmentGroup.traverse((child) => { - if (child instanceof Points || child instanceof Mesh) { - child.material.opacity = dragSelected ? 0 : 1 - } - }) - } - return - } - sceneInfra.highlightCallback([0, 0]) - }, - onMouseLeave: ({ selected }: OnMouseEnterLeaveArgs) => { - sceneInfra.highlightCallback([0, 0]) - const parent = getParentGroup(selected, [ - STRAIGHT_SEGMENT, - TANGENTIAL_ARC_TO_SEGMENT, - PROFILE_START, - ]) - const isSelected = parent?.userData?.isSelected - colorSegment( - selected, - isSelected ? 0x0000ff : parent?.userData?.baseColor || 0xffffff - ) - const extraSegmentGroup = parent?.getObjectByName(EXTRA_SEGMENT_HANDLE) - if (extraSegmentGroup) { - extraSegmentGroup.traverse((child) => { - if (child instanceof Points || child instanceof Mesh) { - child.material.opacity = 0 - } - }) - } - if ([X_AXIS, Y_AXIS].includes(selected?.userData?.type)) { - const obj = selected as Mesh - const mat = obj.material as MeshBasicMaterial - mat.color.set(obj.userData.baseColor) - if (obj.userData.isSelected) mat.color.offsetHSL(0, 0, 0.2) - } - }, - } -} diff --git a/src/clientSideScene/sceneInfra.ts b/src/clientSideScene/sceneInfra.ts index 508de5ea61..0a42686dce 100644 --- a/src/clientSideScene/sceneInfra.ts +++ b/src/clientSideScene/sceneInfra.ts @@ -372,13 +372,12 @@ export class SceneInfra { if (intersects[0]) { const firstIntersectObject = intersects[0].object if (this.hoveredObject !== firstIntersectObject) { - if (this.hoveredObject) { - this.onMouseLeave({ - selected: this.hoveredObject, - mouseEvent: mouseEvent, - }) - if (!this.selected) this.updateMouseState({ type: 'idle' }) - } + const hoveredObj = this.hoveredObject + this.hoveredObject = null + this.onMouseLeave({ + selected: hoveredObj, + mouseEvent: mouseEvent, + }) this.hoveredObject = firstIntersectObject this.onMouseEnter({ selected: this.hoveredObject, @@ -393,13 +392,14 @@ export class SceneInfra { } } else { if (this.hoveredObject) { + const hoveredObj = this.hoveredObject + this.hoveredObject = null this.onMouseLeave({ - selected: this.hoveredObject, + selected: hoveredObj, dragSelected: this.selected?.object, mouseEvent: mouseEvent, }) if (!this.selected) this.updateMouseState({ type: 'idle' }) - this.hoveredObject = null } } } diff --git a/src/clientSideScene/segments.ts b/src/clientSideScene/segments.ts index 3982ec33b2..adf89610d8 100644 --- a/src/clientSideScene/segments.ts +++ b/src/clientSideScene/segments.ts @@ -25,7 +25,7 @@ import { PathToNode, SketchGroup, getTangentialArcToInfo } from 'lang/wasm' import { EXTRA_SEGMENT_HANDLE, EXTRA_SEGMENT_OFFSET_PX, - MIN_SEGMENT_LENGTH, + HIDE_SEGMENT_LENGTH, PROFILE_START, SEGMENT_WIDTH_PX, STRAIGHT_SEGMENT, @@ -141,7 +141,7 @@ export function straightSegment({ .normalize() arrowGroup.quaternion.setFromUnitVectors(new Vector3(0, 1, 0), dir) const pxLength = length / scale - const shouldHide = pxLength < MIN_SEGMENT_LENGTH + const shouldHide = pxLength < HIDE_SEGMENT_LENGTH arrowGroup.visible = !shouldHide group.add(mesh) @@ -282,7 +282,7 @@ export function tangentialArcToSegment({ new Vector3(Math.cos(arrowheadAngle), Math.sin(arrowheadAngle), 0) ) const pxLength = arcLength / scale - const shouldHide = pxLength < MIN_SEGMENT_LENGTH + const shouldHide = pxLength < HIDE_SEGMENT_LENGTH arrowGroup.visible = !shouldHide const extraSegmentGroup = createExtraSegmentHandle(scale, texture) From 4e3176fccaa9abb5b447e8791e7bb40a494d027e Mon Sep 17 00:00:00 2001 From: Kurt Hutten Irev-Dev Date: Wed, 3 Apr 2024 15:13:55 +1100 Subject: [PATCH 3/8] bump min length --- src/clientSideScene/sceneEntities.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clientSideScene/sceneEntities.ts b/src/clientSideScene/sceneEntities.ts index e08d076b4a..1b00c5edbb 100644 --- a/src/clientSideScene/sceneEntities.ts +++ b/src/clientSideScene/sceneEntities.ts @@ -100,7 +100,7 @@ export const TANGENTIAL_ARC_TO_SEGMENT = 'tangential-arc-to-segment' export const TANGENTIAL_ARC_TO_SEGMENT_BODY = 'tangential-arc-to-segment-body' export const SEGMENT_WIDTH_PX = 1.6 export const HIDE_SEGMENT_LENGTH = 60 // in pixels -export const HIDE_HOVER_SEGMENT_LENGTH = 35 // in pixels +export const HIDE_HOVER_SEGMENT_LENGTH = 40 // in pixels // This singleton Class is responsible for all of the things the user sees and interacts with. // That mostly mean sketch elements. From 77a8fe30808c0a137ef37a87f42264c01c616f6c Mon Sep 17 00:00:00 2001 From: Kurt Hutten Irev-Dev Date: Wed, 3 Apr 2024 15:16:37 +1100 Subject: [PATCH 4/8] clean up --- src/clientSideScene/sceneEntities.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/clientSideScene/sceneEntities.ts b/src/clientSideScene/sceneEntities.ts index 1b00c5edbb..1552d177a2 100644 --- a/src/clientSideScene/sceneEntities.ts +++ b/src/clientSideScene/sceneEntities.ts @@ -990,9 +990,6 @@ export class SceneEntities { if (hoveredParent && hoveredParent?.uuid === group?.uuid) { isHandlesVisible = !shouldHideHover } - if (isHandlesVisible) { - console.log('hoverGuy', hoveredParent, sceneInfra.hoveredObject, group) - } if (arrowGroup) { arrowGroup.position.set(to[0], to[1], 0) @@ -1263,7 +1260,6 @@ export class SceneEntities { TANGENTIAL_ARC_TO_SEGMENT, PROFILE_START, ]) - console.log('onMouseLeave', parent, selected, rest) if (parent) { const orthoFactor = orthoScale(sceneInfra.camControls.camera) From 40ad5e6aa66b296455c09d3ed7dae05342a0c72f Mon Sep 17 00:00:00 2001 From: Kurt Hutten Irev-Dev Date: Wed, 3 Apr 2024 18:35:05 +1100 Subject: [PATCH 5/8] sketch on face failing randomly --- e2e/playwright/flow-tests.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/e2e/playwright/flow-tests.spec.ts b/e2e/playwright/flow-tests.spec.ts index a998f33c79..8dc854e484 100644 --- a/e2e/playwright/flow-tests.spec.ts +++ b/e2e/playwright/flow-tests.spec.ts @@ -1533,6 +1533,7 @@ test('Sketch on face', async ({ page, context }) => { await page.getByRole('button', { name: 'Extrude' }).click() await expect(page.getByTestId('command-bar')).toBeVisible() + await page.waitForTimeout(100) await page.keyboard.press('Enter') await expect(page.getByText('Confirm Extrude')).toBeVisible() From 93742618a7b97b1c563ef22fce2bf8473d70fc1a Mon Sep 17 00:00:00 2001 From: Kurt Hutten Irev-Dev Date: Wed, 3 Apr 2024 18:51:33 +1100 Subject: [PATCH 6/8] more time out for extrude snapshots --- e2e/playwright/snapshot-tests.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e/playwright/snapshot-tests.spec.ts b/e2e/playwright/snapshot-tests.spec.ts index 35a6e870c4..8725d0f42a 100644 --- a/e2e/playwright/snapshot-tests.spec.ts +++ b/e2e/playwright/snapshot-tests.spec.ts @@ -363,14 +363,14 @@ test('extrude on each default plane should be stable', async ({ // clear code await u.removeCurrentCode() // add makeCode('XZ') + await u.openAndClearDebugPanel() await page.locator('.cm-content').fill(makeCode(plane)) // wait for execution done - await u.openDebugPanel() await u.expectCmdLog('[data-message-type="execution-done"]') await u.clearAndCloseDebugPanel() await page.getByText('Code').click() - await page.waitForTimeout(80) + await page.waitForTimeout(150) await expect(page).toHaveScreenshot({ maxDiffPixels: 100, }) From e6ea134c9b7cc72d0b23fff243bc80ca0095cf19 Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Thu, 4 Apr 2024 06:02:26 +1100 Subject: [PATCH 7/8] Update src/clientSideScene/sceneEntities.ts Co-authored-by: Frank Noirot --- src/clientSideScene/sceneEntities.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/clientSideScene/sceneEntities.ts b/src/clientSideScene/sceneEntities.ts index 1552d177a2..583992136a 100644 --- a/src/clientSideScene/sceneEntities.ts +++ b/src/clientSideScene/sceneEntities.ts @@ -99,8 +99,8 @@ export const TANGENTIAL_ARC_TO__SEGMENT_DASH = export const TANGENTIAL_ARC_TO_SEGMENT = 'tangential-arc-to-segment' export const TANGENTIAL_ARC_TO_SEGMENT_BODY = 'tangential-arc-to-segment-body' export const SEGMENT_WIDTH_PX = 1.6 -export const HIDE_SEGMENT_LENGTH = 60 // in pixels -export const HIDE_HOVER_SEGMENT_LENGTH = 40 // in pixels +export const HIDE_SEGMENT_LENGTH = 75 // in pixels +export const HIDE_HOVER_SEGMENT_LENGTH = 60 // in pixels // This singleton Class is responsible for all of the things the user sees and interacts with. // That mostly mean sketch elements. From 41e3ec75d4cdbe2163b37ee0657a5e7aa2ea23ce Mon Sep 17 00:00:00 2001 From: Kurt Hutten Irev-Dev Date: Thu, 4 Apr 2024 10:45:13 +1100 Subject: [PATCH 8/8] move for profileStart handle, and select when no tool equiped --- src/clientSideScene/ClientSideSceneComp.tsx | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/clientSideScene/ClientSideSceneComp.tsx b/src/clientSideScene/ClientSideSceneComp.tsx index b9d5c53c35..caefa72b86 100644 --- a/src/clientSideScene/ClientSideSceneComp.tsx +++ b/src/clientSideScene/ClientSideSceneComp.tsx @@ -8,7 +8,11 @@ import { ARROWHEAD, DEBUG_SHOW_BOTH_SCENES } from './sceneInfra' import { ReactCameraProperties } from './CameraControls' import { throttle } from 'lib/utils' import { sceneInfra } from 'lib/singletons' -import { EXTRA_SEGMENT_HANDLE, getParentGroup } from './sceneEntities' +import { + EXTRA_SEGMENT_HANDLE, + PROFILE_START, + getParentGroup, +} from './sceneEntities' function useShouldHideScene(): { hideClient: boolean; hideServer: boolean } { const [isCamMoving, setIsCamMoving] = useState(false) @@ -81,13 +85,22 @@ export const ClientSideScene = ({ if (state.matches('Sketch')) { if ( context.mouseState.type === 'isHovering' && - getParentGroup(context.mouseState.on, [ARROWHEAD, EXTRA_SEGMENT_HANDLE]) + getParentGroup(context.mouseState.on, [ + ARROWHEAD, + EXTRA_SEGMENT_HANDLE, + PROFILE_START, + ]) ) { cursor = 'move' } else if (context.mouseState.type === 'isDragging') { cursor = 'grabbing' - } else { + } else if ( + state.matches('Sketch.Line tool') || + state.matches('Sketch.Tangential arc to') + ) { cursor = 'crosshair' + } else { + cursor = 'default' } }