feat(editor): draggable move handle for wall-hosted doors & windows
Doors and windows could only be moved via the floating action menu — their 3D handle rig declared width/height resize arrows but no move grip, and Ctrl/Meta-drag was a no-op for them. Add a press-drag move cross and make direct-drag work for every bespoke-mover kind. - door/window: add a `tap-action` `move-cross` handle (plane node-normal, portal grandparent, `engageMoveDrag`) mirroring the item wall grip. It routes through the existing per-kind move tool (3D `affordanceTools.move`, 2D `floorplanMoveTarget`) — wall-bound slide + re-host onto another wall — so the grip, the floating Move button, and the 2D plan's move dot share one pipeline. Grab-drag-release commits without a second click. - canDirectMoveNode: gate Ctrl/Meta-drag on `movable || affordanceTools.move` (the 3D-mountable move paths) instead of `movable` only, so doors/windows/ walls/slabs/stairs/… are draggable in 3D as they already are in 2D. Floorplan-only movers (zone) stay excluded — no 3D tool mounts. The floating helper auto-syncs (it reads canDirectMoveNode). - TapActionArrow: honor `plane: 'node-normal'` by tilting the move cross [π/2,0,0] into the wall face — previously ignored, so the item wall grip rendered flat too. Now door/window/wall-item crosses lie in the wall. - use-node-events: split the drag-suppression gate. `inputDragging` still suppresses SELECTION events (the synthesized release-click would re-select), but no longer suppresses SPATIAL events (enter/move/leave) — a surface-following move tool runs with `inputDragging` set and needs wall:move to track the cursor. General consumers that must ignore drags (viewer hover, box-select) already self-gate on `inputDragging`; the editor's select-hover and paint-preview enter handlers now gate on it too. - handle-arrow: make handle hit areas inert while `placementDragMode` is set, so a move grip riding the dragged node can't intercept the ray and starve the move tool's surface raycast. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
cf24b62c44
commit
1f829d52ed
@@ -19,6 +19,9 @@ const SIDE_HANDLE_OFFSET = 0.24
|
||||
const HEIGHT_HANDLE_OFFSET = 0.24
|
||||
const MIN_DOOR_HEIGHT = 0.5
|
||||
const MIN_DOOR_WIDTH = 0.3
|
||||
// How far the move cross floats off the wall face (+Z, the door's facing
|
||||
// normal) so it's grabbable instead of buried in the leaf/frame.
|
||||
const MOVE_HANDLE_LIFT = 0.12
|
||||
|
||||
function readWallLength(door: DoorNodeType, scene: { get: (id: AnyNodeId) => unknown }): number {
|
||||
if (!door.wallId) return Number.POSITIVE_INFINITY
|
||||
@@ -112,7 +115,26 @@ function doorHeightHandle(): HandleDescriptor<DoorNodeType> {
|
||||
}
|
||||
}
|
||||
|
||||
// Press-drag move grip at the door centre, standing in the wall face. Routes
|
||||
// through the same move tool as the floating Move button (3D
|
||||
// `affordanceTools.move`, 2D `floorplanMoveTarget`) — wall slide + re-host onto
|
||||
// another wall — but `engageMoveDrag` commits on release, with no second click.
|
||||
function doorMoveHandle(): HandleDescriptor<DoorNodeType> {
|
||||
return {
|
||||
kind: 'tap-action',
|
||||
shape: 'move-cross',
|
||||
plane: 'node-normal',
|
||||
portal: 'grandparent',
|
||||
cursor: 'move',
|
||||
onActivate: (node, _scene, editor) => editor.engageMoveDrag(node),
|
||||
placement: {
|
||||
position: () => [0, 0, MOVE_HANDLE_LIFT],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const doorHandles: HandleDescriptor<DoorNodeType>[] = [
|
||||
doorMoveHandle(),
|
||||
doorWidthHandle('left'),
|
||||
doorWidthHandle('right'),
|
||||
doorHeightHandle(),
|
||||
|
||||
Reference in New Issue
Block a user