@pascal-app/editor 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +13 -9
- package/src/components/editor/bottom-sheet.tsx +149 -0
- package/src/components/editor/custom-camera-controls.tsx +74 -5
- package/src/components/editor/editor-layout-mobile.tsx +264 -0
- package/src/components/editor/editor-layout-v2.tsx +24 -3
- package/src/components/editor/first-person/build-collider-world.ts +363 -0
- package/src/components/editor/first-person/bvh-ecctrl.tsx +860 -0
- package/src/components/editor/first-person-controls.tsx +496 -143
- package/src/components/editor/floating-action-menu.tsx +32 -55
- package/src/components/editor/floorplan-background-selection.ts +113 -0
- package/src/components/editor/floorplan-panel.tsx +9861 -3297
- package/src/components/editor/index.tsx +295 -32
- package/src/components/editor/selection-manager.tsx +575 -13
- package/src/components/editor/snapshot-capture-overlay.tsx +465 -0
- package/src/components/editor/thumbnail-generator.tsx +56 -68
- package/src/components/editor/use-floorplan-background-placement.ts +257 -0
- package/src/components/editor/use-floorplan-hit-testing.ts +171 -0
- package/src/components/editor/use-floorplan-scene-data.ts +189 -0
- package/src/components/editor/wall-measurement-label.tsx +267 -36
- package/src/components/editor-2d/floorplan-action-menu-layer.tsx +95 -0
- package/src/components/editor-2d/floorplan-cursor-indicator-overlay.tsx +160 -0
- package/src/components/editor-2d/floorplan-hotkey-handlers.tsx +92 -0
- package/src/components/editor-2d/renderers/floorplan-draft-layer.tsx +124 -0
- package/src/components/editor-2d/renderers/floorplan-marquee-layer.tsx +58 -0
- package/src/components/editor-2d/renderers/floorplan-measurements-layer.tsx +202 -0
- package/src/components/editor-2d/renderers/floorplan-roof-layer.tsx +113 -0
- package/src/components/editor-2d/renderers/floorplan-stair-layer.tsx +474 -0
- package/src/components/editor-2d/svg-paths.ts +119 -0
- package/src/components/systems/ceiling/ceiling-selection-affordance-system.tsx +10 -12
- package/src/components/systems/roof/roof-edit-system.tsx +1 -1
- package/src/components/systems/stair/stair-edit-system.tsx +1 -1
- package/src/components/systems/zone/zone-label-editor-system.tsx +0 -0
- package/src/components/systems/zone/zone-system.tsx +0 -0
- package/src/components/tools/ceiling/ceiling-boundary-editor.tsx +1 -0
- package/src/components/tools/ceiling/ceiling-hole-editor.tsx +1 -0
- package/src/components/tools/ceiling/ceiling-tool.tsx +5 -5
- package/src/components/tools/ceiling/move-ceiling-tool.tsx +9 -2
- package/src/components/tools/column/column-tool.tsx +97 -0
- package/src/components/tools/column/move-column-tool.tsx +105 -0
- package/src/components/tools/door/door-tool.tsx +7 -0
- package/src/components/tools/door/move-door-tool.tsx +28 -8
- package/src/components/tools/fence/curve-fence-tool.tsx +4 -5
- package/src/components/tools/fence/fence-drafting.ts +10 -3
- package/src/components/tools/fence/fence-tool.tsx +160 -4
- package/src/components/tools/fence/move-fence-endpoint-tool.tsx +139 -25
- package/src/components/tools/fence/move-fence-tool.tsx +111 -40
- package/src/components/tools/item/move-tool.tsx +7 -1
- package/src/components/tools/item/placement-math.ts +32 -5
- package/src/components/tools/item/placement-strategies.ts +110 -31
- package/src/components/tools/item/placement-types.ts +7 -0
- package/src/components/tools/item/use-draft-node.ts +1 -0
- package/src/components/tools/item/use-placement-coordinator.tsx +558 -52
- package/src/components/tools/roof/move-roof-tool.tsx +29 -17
- package/src/components/tools/select/box-select-tool.tsx +12 -17
- package/src/components/tools/shared/polygon-editor.tsx +153 -28
- package/src/components/tools/shared/segment-angle.ts +156 -0
- package/src/components/tools/slab/slab-boundary-editor.tsx +1 -0
- package/src/components/tools/slab/slab-hole-editor.tsx +1 -0
- package/src/components/tools/spawn/move-spawn-tool.tsx +101 -0
- package/src/components/tools/spawn/spawn-tool.tsx +130 -0
- package/src/components/tools/tool-manager.tsx +20 -5
- package/src/components/tools/wall/curve-wall-tool.tsx +8 -6
- package/src/components/tools/wall/move-wall-endpoint-tool.tsx +131 -27
- package/src/components/tools/wall/move-wall-tool.tsx +6 -4
- package/src/components/tools/wall/wall-drafting.ts +18 -9
- package/src/components/tools/wall/wall-tool.tsx +136 -4
- package/src/components/tools/window/move-window-tool.tsx +18 -0
- package/src/components/tools/window/window-tool.tsx +5 -0
- package/src/components/tools/zone/zone-tool.tsx +20 -5
- package/src/components/ui/action-menu/camera-actions.tsx +37 -33
- package/src/components/ui/action-menu/control-modes.tsx +34 -1
- package/src/components/ui/action-menu/furnish-tools.tsx +6 -92
- package/src/components/ui/action-menu/index.tsx +98 -59
- package/src/components/ui/action-menu/structure-tools.tsx +2 -0
- package/src/components/ui/action-menu/view-toggles.tsx +418 -41
- package/src/components/ui/command-palette/editor-commands.tsx +24 -5
- package/src/components/ui/command-palette/index.tsx +4 -255
- package/src/components/ui/controls/material-picker.tsx +154 -164
- package/src/components/ui/controls/slider-control.tsx +66 -18
- package/src/components/ui/floating-level-selector.tsx +286 -55
- package/src/components/ui/helpers/helper-manager.tsx +10 -0
- package/src/components/ui/item-catalog/catalog-items.tsx +2563 -1239
- package/src/components/ui/item-catalog/item-catalog.tsx +96 -187
- package/src/components/ui/level-duplicate-dialog.tsx +113 -0
- package/src/components/ui/panels/ceiling-panel.tsx +3 -28
- package/src/components/ui/panels/column-panel.tsx +759 -0
- package/src/components/ui/panels/door-panel.tsx +989 -290
- package/src/components/ui/panels/fence-panel.tsx +2 -49
- package/src/components/ui/panels/mobile-panel-sheet.tsx +108 -0
- package/src/components/ui/panels/mobile-selection-bar.tsx +100 -0
- package/src/components/ui/panels/node-display.ts +39 -0
- package/src/components/ui/panels/paint-panel.tsx +163 -0
- package/src/components/ui/panels/panel-manager.tsx +208 -28
- package/src/components/ui/panels/panel-wrapper.tsx +48 -39
- package/src/components/ui/panels/reference-panel.tsx +253 -5
- package/src/components/ui/panels/roof-panel.tsx +13 -64
- package/src/components/ui/panels/roof-segment-panel.tsx +0 -25
- package/src/components/ui/panels/slab-panel.tsx +4 -30
- package/src/components/ui/panels/spawn-panel.tsx +161 -0
- package/src/components/ui/panels/stair-panel.tsx +20 -74
- package/src/components/ui/panels/stair-segment-panel.tsx +0 -25
- package/src/components/ui/panels/wall-panel.tsx +10 -8
- package/src/components/ui/panels/window-panel.tsx +668 -139
- package/src/components/ui/primitives/number-input.tsx +1 -1
- package/src/components/ui/primitives/sidebar.tsx +0 -0
- package/src/components/ui/sidebar/app-sidebar.tsx +0 -0
- package/src/components/ui/sidebar/icon-rail.tsx +0 -0
- package/src/components/ui/sidebar/mobile-tab-bar.tsx +46 -0
- package/src/components/ui/sidebar/panels/items-panel/index.tsx +330 -0
- package/src/components/ui/sidebar/panels/settings-panel/index.tsx +0 -0
- package/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +2 -2
- package/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx +2 -2
- package/src/components/ui/sidebar/panels/site-panel/ceiling-tree-node.tsx +0 -0
- package/src/components/ui/sidebar/panels/site-panel/column-tree-node.tsx +77 -0
- package/src/components/ui/sidebar/panels/site-panel/index.tsx +105 -22
- package/src/components/ui/sidebar/panels/site-panel/level-tree-node.tsx +2 -2
- package/src/components/ui/sidebar/panels/site-panel/slab-tree-node.tsx +0 -0
- package/src/components/ui/sidebar/panels/site-panel/spawn-tree-node.tsx +76 -0
- package/src/components/ui/sidebar/panels/site-panel/tree-node.tsx +11 -3
- package/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx +10 -5
- package/src/components/ui/sidebar/panels/zone-panel/index.tsx +1 -1
- package/src/components/ui/sidebar/tab-bar.tsx +3 -0
- package/src/components/ui/slider.tsx +1 -1
- package/src/components/viewer-overlay.tsx +0 -0
- package/src/components/viewer-zone-system.tsx +0 -0
- package/src/hooks/use-auto-frame.ts +45 -0
- package/src/hooks/use-auto-save.ts +14 -0
- package/src/hooks/use-keyboard.ts +74 -7
- package/src/hooks/use-mobile.ts +12 -12
- package/src/index.tsx +8 -1
- package/src/lib/door-interaction.ts +88 -0
- package/src/lib/floorplan/geometry.ts +263 -0
- package/src/lib/floorplan/index.ts +38 -0
- package/src/lib/floorplan/items.ts +179 -0
- package/src/lib/floorplan/selection-tool.ts +231 -0
- package/src/lib/floorplan/stairs.ts +478 -0
- package/src/lib/floorplan/types.ts +57 -0
- package/src/lib/floorplan/walls.ts +23 -0
- package/src/lib/guide-events.ts +10 -0
- package/src/lib/level-duplication.test.ts +70 -0
- package/src/lib/level-duplication.ts +153 -0
- package/src/lib/local-guide-image.ts +42 -0
- package/src/lib/material-paint.ts +284 -0
- package/src/lib/roof-duplication.ts +214 -0
- package/src/lib/scene-bounds.test.ts +183 -0
- package/src/lib/scene-bounds.ts +169 -0
- package/src/lib/scene.ts +0 -0
- package/src/lib/sfx-bus.ts +2 -0
- package/src/lib/sfx-player.ts +5 -5
- package/src/lib/stair-duplication.ts +126 -0
- package/src/lib/window-interaction.ts +86 -0
- package/src/store/use-editor.tsx +186 -62
- package/tsconfig.json +2 -1
- package/src/components/feedback-dialog.tsx +0 -265
- package/src/components/pascal-radio.tsx +0 -280
- package/src/components/preview-button.tsx +0 -16
- package/src/components/ui/viewer-toolbar.tsx +0 -395
|
@@ -4,12 +4,14 @@ import {
|
|
|
4
4
|
type AnyNode,
|
|
5
5
|
type AnyNodeId,
|
|
6
6
|
type CeilingNode,
|
|
7
|
+
ColumnNode,
|
|
7
8
|
DoorNode,
|
|
8
9
|
FenceNode,
|
|
10
|
+
generateId,
|
|
9
11
|
ItemNode,
|
|
10
|
-
RoofNode,
|
|
11
12
|
RoofSegmentNode,
|
|
12
13
|
type SlabNode,
|
|
14
|
+
SpawnNode,
|
|
13
15
|
StairNode,
|
|
14
16
|
StairSegmentNode,
|
|
15
17
|
sceneRegistry,
|
|
@@ -23,7 +25,9 @@ import { useFrame } from '@react-three/fiber'
|
|
|
23
25
|
import { Move } from 'lucide-react'
|
|
24
26
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
|
25
27
|
import * as THREE from 'three'
|
|
28
|
+
import { duplicateRoofSubtree } from '../../lib/roof-duplication'
|
|
26
29
|
import { sfxEmitter } from '../../lib/sfx-bus'
|
|
30
|
+
import { duplicateStairSubtree } from '../../lib/stair-duplication'
|
|
27
31
|
import useEditor from '../../store/use-editor'
|
|
28
32
|
import { NodeActionMenu } from './node-action-menu'
|
|
29
33
|
|
|
@@ -37,8 +41,10 @@ const ALLOWED_TYPES = [
|
|
|
37
41
|
'stair-segment',
|
|
38
42
|
'wall',
|
|
39
43
|
'fence',
|
|
44
|
+
'column',
|
|
40
45
|
'slab',
|
|
41
46
|
'ceiling',
|
|
47
|
+
'spawn',
|
|
42
48
|
]
|
|
43
49
|
const DELETE_ONLY_TYPES: string[] = []
|
|
44
50
|
const HOLE_TYPES = ['slab', 'ceiling']
|
|
@@ -143,10 +149,7 @@ export function FloatingActionMenu() {
|
|
|
143
149
|
node.type === 'wall'
|
|
144
150
|
? obj.localToWorld(
|
|
145
151
|
new THREE.Vector3(
|
|
146
|
-
Math.hypot(
|
|
147
|
-
segment.end[0] - segment.start[0],
|
|
148
|
-
segment.end[1] - segment.start[1],
|
|
149
|
-
),
|
|
152
|
+
Math.hypot(segment.end[0] - segment.start[0], segment.end[1] - segment.start[1]),
|
|
150
153
|
0,
|
|
151
154
|
0,
|
|
152
155
|
),
|
|
@@ -182,8 +185,10 @@ export function FloatingActionMenu() {
|
|
|
182
185
|
node.type === 'door' ||
|
|
183
186
|
node.type === 'wall' ||
|
|
184
187
|
node.type === 'fence' ||
|
|
188
|
+
node.type === 'column' ||
|
|
185
189
|
node.type === 'slab' ||
|
|
186
190
|
node.type === 'ceiling' ||
|
|
191
|
+
node.type === 'spawn' ||
|
|
187
192
|
node.type === 'roof' ||
|
|
188
193
|
node.type === 'roof-segment' ||
|
|
189
194
|
node.type === 'stair' ||
|
|
@@ -234,6 +239,16 @@ export function FloatingActionMenu() {
|
|
|
234
239
|
e.stopPropagation()
|
|
235
240
|
if (!node?.parentId) return
|
|
236
241
|
sfxEmitter.emit('sfx:item-pick')
|
|
242
|
+
|
|
243
|
+
if (node.type === 'roof') {
|
|
244
|
+
try {
|
|
245
|
+
duplicateRoofSubtree(node.id as AnyNodeId, { mode: 'move' })
|
|
246
|
+
} catch (error) {
|
|
247
|
+
console.error('Failed to duplicate roof', error)
|
|
248
|
+
}
|
|
249
|
+
return
|
|
250
|
+
}
|
|
251
|
+
|
|
237
252
|
useScene.temporal.getState().pause()
|
|
238
253
|
|
|
239
254
|
let duplicateInfo = structuredClone(node) as any
|
|
@@ -248,16 +263,16 @@ export function FloatingActionMenu() {
|
|
|
248
263
|
duplicate = WindowNode.parse(duplicateInfo)
|
|
249
264
|
} else if (node.type === 'item') {
|
|
250
265
|
duplicate = ItemNode.parse(duplicateInfo)
|
|
266
|
+
} else if (node.type === 'column') {
|
|
267
|
+
duplicate = ColumnNode.parse(duplicateInfo)
|
|
251
268
|
} else if (node.type === 'wall') {
|
|
252
269
|
duplicate = WallNode.parse(duplicateInfo)
|
|
253
270
|
} else if (node.type === 'fence') {
|
|
254
271
|
duplicate = FenceNode.parse(duplicateInfo)
|
|
255
272
|
duplicate.start = [duplicate.start[0] + 1, duplicate.start[1] + 1]
|
|
256
273
|
duplicate.end = [duplicate.end[0] + 1, duplicate.end[1] + 1]
|
|
257
|
-
} else if (node.type === 'roof') {
|
|
258
|
-
duplicateInfo.children = []
|
|
259
|
-
duplicate = RoofNode.parse(duplicateInfo)
|
|
260
274
|
} else if (node.type === 'roof-segment') {
|
|
275
|
+
duplicateInfo.id = generateId('rseg')
|
|
261
276
|
duplicate = RoofSegmentNode.parse(duplicateInfo)
|
|
262
277
|
} else if (node.type === 'stair') {
|
|
263
278
|
duplicateInfo.children = []
|
|
@@ -266,6 +281,8 @@ export function FloatingActionMenu() {
|
|
|
266
281
|
duplicate = StairNode.parse(duplicateInfo)
|
|
267
282
|
} else if (node.type === 'stair-segment') {
|
|
268
283
|
duplicate = StairSegmentNode.parse(duplicateInfo)
|
|
284
|
+
} else if (node.type === 'spawn') {
|
|
285
|
+
duplicate = SpawnNode.parse(duplicateInfo)
|
|
269
286
|
}
|
|
270
287
|
} catch (error) {
|
|
271
288
|
console.error('Failed to parse duplicate', error)
|
|
@@ -286,7 +303,6 @@ export function FloatingActionMenu() {
|
|
|
286
303
|
} else if (duplicate.type === 'fence') {
|
|
287
304
|
useScene.getState().createNode(duplicate, duplicate.parentId as AnyNodeId)
|
|
288
305
|
} else if (
|
|
289
|
-
duplicate.type === 'roof' ||
|
|
290
306
|
duplicate.type === 'roof-segment' ||
|
|
291
307
|
duplicate.type === 'stair' ||
|
|
292
308
|
duplicate.type === 'stair-segment'
|
|
@@ -300,64 +316,22 @@ export function FloatingActionMenu() {
|
|
|
300
316
|
]
|
|
301
317
|
}
|
|
302
318
|
if (node.type === 'stair' && duplicate.type === 'stair') {
|
|
303
|
-
|
|
304
|
-
const createOps: { node: AnyNode; parentId?: AnyNodeId }[] = [
|
|
305
|
-
{ node: duplicate, parentId: duplicate.parentId as AnyNodeId },
|
|
306
|
-
]
|
|
307
|
-
|
|
308
|
-
for (const childId of node.children ?? []) {
|
|
309
|
-
const childNode = nodesState[childId]
|
|
310
|
-
if (childNode?.type !== 'stair-segment') {
|
|
311
|
-
continue
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
let childDuplicateInfo = structuredClone(childNode) as any
|
|
315
|
-
delete childDuplicateInfo.id
|
|
316
|
-
childDuplicateInfo.metadata = { ...childDuplicateInfo.metadata }
|
|
317
|
-
delete childDuplicateInfo.metadata?.isNew
|
|
318
|
-
|
|
319
|
-
try {
|
|
320
|
-
const childDuplicate = StairSegmentNode.parse(childDuplicateInfo)
|
|
321
|
-
createOps.push({ node: childDuplicate, parentId: duplicate.id as AnyNodeId })
|
|
322
|
-
} catch (e) {
|
|
323
|
-
console.error('Failed to duplicate stair segment', e)
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
useScene.getState().createNodes(createOps)
|
|
319
|
+
duplicateStairSubtree(node.id as AnyNodeId, { mode: 'move' })
|
|
328
320
|
} else {
|
|
329
321
|
useScene.getState().createNode(duplicate, duplicate.parentId as AnyNodeId)
|
|
330
322
|
}
|
|
331
323
|
|
|
332
|
-
// Duplicate children for roof nodes
|
|
333
|
-
if (node.type === 'roof' && node.children) {
|
|
334
|
-
const nodesState = useScene.getState().nodes
|
|
335
|
-
for (const childId of node.children) {
|
|
336
|
-
const childNode = nodesState[childId]
|
|
337
|
-
if (childNode && childNode.type === 'roof-segment') {
|
|
338
|
-
let childDuplicateInfo = structuredClone(childNode) as any
|
|
339
|
-
delete childDuplicateInfo.id
|
|
340
|
-
childDuplicateInfo.metadata = { ...childDuplicateInfo.metadata, isNew: true }
|
|
341
|
-
try {
|
|
342
|
-
const childDuplicate = RoofSegmentNode.parse(childDuplicateInfo)
|
|
343
|
-
useScene.getState().createNode(childDuplicate, duplicate.id as AnyNodeId)
|
|
344
|
-
} catch (e) {
|
|
345
|
-
console.error('Failed to duplicate roof segment', e)
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
|
|
351
324
|
// Duplicate children for stair nodes
|
|
352
325
|
}
|
|
353
326
|
if (
|
|
354
327
|
duplicate.type === 'item' ||
|
|
328
|
+
duplicate.type === 'column' ||
|
|
355
329
|
duplicate.type === 'wall' ||
|
|
356
330
|
duplicate.type === 'fence' ||
|
|
357
331
|
duplicate.type === 'window' ||
|
|
358
332
|
duplicate.type === 'door' ||
|
|
359
|
-
duplicate.type === 'roof' ||
|
|
360
333
|
duplicate.type === 'roof-segment' ||
|
|
334
|
+
duplicate.type === 'spawn' ||
|
|
361
335
|
duplicate.type === 'stair-segment'
|
|
362
336
|
) {
|
|
363
337
|
setMovingNode(duplicate as any)
|
|
@@ -453,7 +427,10 @@ export function FloatingActionMenu() {
|
|
|
453
427
|
}
|
|
454
428
|
onDelete={handleDelete}
|
|
455
429
|
onDuplicate={
|
|
456
|
-
node &&
|
|
430
|
+
node &&
|
|
431
|
+
node.type !== 'spawn' &&
|
|
432
|
+
!DELETE_ONLY_TYPES.includes(node.type) &&
|
|
433
|
+
!HOLE_TYPES.includes(node.type)
|
|
457
434
|
? handleDuplicate
|
|
458
435
|
: undefined
|
|
459
436
|
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import type { Point2D, ZoneNode as ZoneNodeType } from '@pascal-app/core'
|
|
4
|
+
import { isPointInsidePolygon } from '../../lib/floorplan'
|
|
5
|
+
import type { WallPlanPoint } from '../tools/wall/wall-drafting'
|
|
6
|
+
|
|
7
|
+
type ModifierKeys = {
|
|
8
|
+
meta: boolean
|
|
9
|
+
ctrl: boolean
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type ZoneHitEntry = {
|
|
13
|
+
zone: {
|
|
14
|
+
id: ZoneNodeType['id']
|
|
15
|
+
}
|
|
16
|
+
polygon: Point2D[]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
type ResolveFloorplanBackgroundSelectionArgs = {
|
|
20
|
+
canSelectElementFloorplanGeometry: boolean
|
|
21
|
+
canSelectFloorplanZones: boolean
|
|
22
|
+
currentSelectedIds: string[]
|
|
23
|
+
getFloorplanHitIdAtPoint: (planPoint: WallPlanPoint) => string | null
|
|
24
|
+
isWallBuildActive: boolean
|
|
25
|
+
modifierKeys: ModifierKeys
|
|
26
|
+
planPoint: WallPlanPoint
|
|
27
|
+
structureLayer: string
|
|
28
|
+
toPoint2D: (point: WallPlanPoint) => Point2D
|
|
29
|
+
visibleZonePolygons: ZoneHitEntry[]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type FloorplanBackgroundSelectionResult =
|
|
33
|
+
| {
|
|
34
|
+
handled: true
|
|
35
|
+
kind: 'select-zone'
|
|
36
|
+
zoneId: ZoneNodeType['id']
|
|
37
|
+
}
|
|
38
|
+
| {
|
|
39
|
+
handled: true
|
|
40
|
+
kind: 'select-elements'
|
|
41
|
+
selectedIds: string[]
|
|
42
|
+
}
|
|
43
|
+
| {
|
|
44
|
+
handled: true
|
|
45
|
+
kind: 'clear-zones'
|
|
46
|
+
}
|
|
47
|
+
| {
|
|
48
|
+
handled: true
|
|
49
|
+
kind: 'clear-elements'
|
|
50
|
+
preserveSelection: boolean
|
|
51
|
+
}
|
|
52
|
+
| {
|
|
53
|
+
handled: false
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function resolveFloorplanBackgroundSelection({
|
|
57
|
+
canSelectElementFloorplanGeometry,
|
|
58
|
+
canSelectFloorplanZones,
|
|
59
|
+
currentSelectedIds,
|
|
60
|
+
getFloorplanHitIdAtPoint,
|
|
61
|
+
isWallBuildActive,
|
|
62
|
+
modifierKeys,
|
|
63
|
+
planPoint,
|
|
64
|
+
structureLayer,
|
|
65
|
+
toPoint2D,
|
|
66
|
+
visibleZonePolygons,
|
|
67
|
+
}: ResolveFloorplanBackgroundSelectionArgs): FloorplanBackgroundSelectionResult {
|
|
68
|
+
if (canSelectFloorplanZones) {
|
|
69
|
+
const zoneHit = visibleZonePolygons.find(({ polygon }) =>
|
|
70
|
+
isPointInsidePolygon(toPoint2D(planPoint), polygon),
|
|
71
|
+
)
|
|
72
|
+
if (zoneHit) {
|
|
73
|
+
return {
|
|
74
|
+
handled: true,
|
|
75
|
+
kind: 'select-zone',
|
|
76
|
+
zoneId: zoneHit.zone.id,
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (canSelectElementFloorplanGeometry) {
|
|
82
|
+
const hitId = getFloorplanHitIdAtPoint(planPoint)
|
|
83
|
+
if (hitId) {
|
|
84
|
+
return {
|
|
85
|
+
handled: true,
|
|
86
|
+
kind: 'select-elements',
|
|
87
|
+
selectedIds:
|
|
88
|
+
modifierKeys.meta || modifierKeys.ctrl
|
|
89
|
+
? currentSelectedIds.includes(hitId)
|
|
90
|
+
? currentSelectedIds.filter((selectedId) => selectedId !== hitId)
|
|
91
|
+
: [...currentSelectedIds, hitId]
|
|
92
|
+
: [hitId],
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (!isWallBuildActive) {
|
|
98
|
+
if (structureLayer === 'zones') {
|
|
99
|
+
return {
|
|
100
|
+
handled: true,
|
|
101
|
+
kind: 'clear-zones',
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
handled: true,
|
|
107
|
+
kind: 'clear-elements',
|
|
108
|
+
preserveSelection: modifierKeys.meta || modifierKeys.ctrl,
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return { handled: false }
|
|
113
|
+
}
|