Refactor guide events and column placement handling

This commit is contained in:
sudhir
2026-05-04 23:06:23 +05:30
parent db765f1eb3
commit 762c9fc763
8 changed files with 224 additions and 210 deletions
@@ -64,6 +64,7 @@ import {
rotatePlanVector as rotateSharedPlanVector,
type FloorplanNodeTransform as SharedFloorplanNodeTransform,
} from '../../lib/floorplan'
import { guideEmitter } from '../../lib/guide-events'
import { duplicateRoofSubtree } from '../../lib/roof-duplication'
import { sfxEmitter } from '../../lib/sfx-bus'
import { duplicateStairSubtree } from '../../lib/stair-duplication'
@@ -9131,9 +9132,9 @@ export function FloorplanPanel() {
}
}
emitter.on('guide:set-reference-scale', handleSetReferenceScale)
guideEmitter.on('guide:set-reference-scale', handleSetReferenceScale)
return () => {
emitter.off('guide:set-reference-scale', handleSetReferenceScale)
guideEmitter.off('guide:set-reference-scale', handleSetReferenceScale)
}
}, [startReferenceScaleForGuide])
@@ -9143,9 +9144,9 @@ export function FloorplanPanel() {
setPendingReferenceScale(null)
}
emitter.on('guide:cancel-reference-scale', handleCancel)
guideEmitter.on('guide:cancel-reference-scale', handleCancel)
return () => {
emitter.off('guide:cancel-reference-scale', handleCancel)
guideEmitter.off('guide:cancel-reference-scale', handleCancel)
}
}, [])
@@ -9160,9 +9161,9 @@ export function FloorplanPanel() {
clearGuideUi(payload.guideId)
}
emitter.on('guide:deleted', handleDeleted)
guideEmitter.on('guide:deleted', handleDeleted)
return () => {
emitter.off('guide:deleted', handleDeleted)
guideEmitter.off('guide:deleted', handleDeleted)
}
}, [clearGuideUi])
@@ -1,16 +1,15 @@
import '../../../three-types'
import {
type AnyNode,
COLUMN_PRESETS,
ColumnNode,
type ColumnNode as ColumnNodeType,
type ColumnPresetId,
emitter,
type GridEvent,
type LevelNode,
useScene,
} from '@pascal-app/core'
import { useViewer } from '@pascal-app/viewer'
import { useEffect, useRef, useState } from 'react'
import type { Group } from 'three'
import { sfxEmitter } from '../../../lib/sfx-bus'
@@ -41,9 +40,10 @@ function createColumnFromPreset(presetId: ColumnPresetId, position: [number, num
type ColumnToolProps = {
currentLevelId: LevelNode['id'] | null
onPlaced?: (nodeId: ColumnNodeType['id']) => void
}
export const ColumnTool: React.FC<ColumnToolProps> = ({ currentLevelId }) => {
export const ColumnTool: React.FC<ColumnToolProps> = ({ currentLevelId, onPlaced }) => {
const [, setCursorPosition] = useState<[number, number, number] | null>(null)
const cursorRef = useRef<Group>(null)
@@ -68,7 +68,7 @@ export const ColumnTool: React.FC<ColumnToolProps> = ({ currentLevelId }) => {
]
const column = createColumnFromPreset(DEFAULT_COLUMN_PRESET_ID, position)
useScene.getState().createNode(column, currentLevelId)
useViewer.getState().setSelection({ selectedIds: [column.id as AnyNode['id']] })
onPlaced?.(column.id)
sfxEmitter.emit('sfx:structure-build')
useEditor.getState().setTool(null)
useEditor.getState().setMode('select')
@@ -81,7 +81,7 @@ export const ColumnTool: React.FC<ColumnToolProps> = ({ currentLevelId }) => {
emitter.off('grid:move', onGridMove)
emitter.off('grid:click', onGridClick)
}
}, [currentLevelId])
}, [currentLevelId, onPlaced])
if (!currentLevelId) return null
@@ -127,7 +127,7 @@ export const ToolManager: React.FC = () => {
const showBuildTool = mode === 'build' && tool !== null
const BuildToolComponent = showBuildTool ? tools[phase]?.[tool] : null
const handleSpawnSelected = (nodeId: `spawn_${string}`) => {
const handlePlacedNodeSelected = (nodeId: AnyNodeId) => {
setSelection({ selectedIds: [nodeId] })
}
@@ -135,7 +135,7 @@ export const ToolManager: React.FC = () => {
<>
{showSiteBoundaryEditor && <SiteBoundaryEditor />}
{/* World-space tools: site boundary and building movement operate in world coordinates */}
{movingNode?.type === 'building' && <MoveTool onSpawnMoved={handleSpawnSelected} />}
{movingNode?.type === 'building' && <MoveTool onSpawnMoved={handlePlacedNodeSelected} />}
{/* Building-local group: all other tools are relative to the selected building.
Cursor visuals set positions in building-local space; this group applies the
@@ -160,13 +160,13 @@ export const ToolManager: React.FC = () => {
{curvingWall && <CurveWallTool node={curvingWall} />}
{curvingFence && <CurveFenceTool node={curvingFence} />}
{movingNode && movingNode.type !== 'building' && (
<MoveTool onSpawnMoved={handleSpawnSelected} />
<MoveTool onSpawnMoved={handlePlacedNodeSelected} />
)}
{!movingNode && showBuildTool && tool === 'spawn' && (
<SpawnTool currentLevelId={selectedLevelId} onPlaced={handleSpawnSelected} />
<SpawnTool currentLevelId={selectedLevelId} onPlaced={handlePlacedNodeSelected} />
)}
{!movingNode && showBuildTool && tool === 'column' && (
<ColumnTool currentLevelId={selectedLevelId} />
<ColumnTool currentLevelId={selectedLevelId} onPlaced={handlePlacedNodeSelected} />
)}
{!movingNode && BuildToolComponent && tool !== 'column' && <BuildToolComponent />}
</group>
@@ -2,7 +2,6 @@
import {
type AnyNode,
emitter,
type GuideNode,
loadAssetUrl,
saveAsset,
@@ -11,6 +10,7 @@ import {
} from '@pascal-app/core'
import { Eye, EyeOff, LocateFixed, Lock, RotateCcw, Ruler, Trash2, Unlock, Upload } from 'lucide-react'
import { useCallback, useEffect, useRef, useState } from 'react'
import { guideEmitter } from '../../../lib/guide-events'
import { getGuideImageName } from '../../../lib/local-guide-image'
import useEditor from '../../../store/use-editor'
import { ActionButton, ActionGroup } from '../controls/action-button'
@@ -98,7 +98,7 @@ export function ReferencePanel() {
}
deleteNode(selectedReferenceId as AnyNode['id'])
emitter.emit('guide:deleted', { guideId: selectedReferenceId as GuideNode['id'] })
guideEmitter.emit('guide:deleted', { guideId: selectedReferenceId as GuideNode['id'] })
clearGuideUi(selectedReferenceId)
setSelectedReferenceId(null)
}, [clearGuideUi, deleteNode, node?.type, selectedReferenceId, setSelectedReferenceId])
@@ -108,11 +108,11 @@ export function ReferencePanel() {
return
}
emitter.emit('guide:set-reference-scale', { guideId: node.id })
guideEmitter.emit('guide:set-reference-scale', { guideId: node.id })
}, [node])
const handleCancelScale = useCallback(() => {
emitter.emit('guide:cancel-reference-scale')
guideEmitter.emit('guide:cancel-reference-scale')
}, [])
useEffect(() => {
+10
View File
@@ -0,0 +1,10 @@
import type { GuideNode } from '@pascal-app/core'
import mitt from 'mitt'
type GuideEditorEvents = {
'guide:set-reference-scale': { guideId: GuideNode['id'] }
'guide:cancel-reference-scale': undefined
'guide:deleted': { guideId: GuideNode['id'] }
}
export const guideEmitter = mitt<GuideEditorEvents>()